pax_global_header00006660000000000000000000000064150176131060014512gustar00rootroot0000000000000052 comment=97c4ec3d68b5b199f2796d1e126c2144506bd228 audit-userspace-4.0.5/000077500000000000000000000000001501761310600146165ustar00rootroot00000000000000audit-userspace-4.0.5/.gitattributes000066400000000000000000000000061501761310600175050ustar00rootroot00000000000000* textaudit-userspace-4.0.5/.github/000077500000000000000000000000001501761310600161565ustar00rootroot00000000000000audit-userspace-4.0.5/.github/ISSUE_TEMPLATE.md000066400000000000000000000003301501761310600206570ustar00rootroot00000000000000**NOTE:** Please refer to the [Reporting Bug and Requesting Features](https://github.com/linux-audit/audit-documentation/wiki/Reporting-Bugs-and-Requesting-Features) wiki page before creating any new GitHub issues. audit-userspace-4.0.5/.github/workflows/000077500000000000000000000000001501761310600202135ustar00rootroot00000000000000audit-userspace-4.0.5/.github/workflows/ci.yml000066400000000000000000000034301501761310600213310ustar00rootroot00000000000000name: CI Matrix on: push: branches: [main, githubactions] pull_request: branches: [main, githubactions] jobs: build-and-test: runs-on: ubuntu-latest container: ${{ matrix.container }} strategy: fail-fast: false matrix: container: ['ubuntu:latest', 'fedora:latest'] compiler: [gcc, clang] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies (Ubuntu) if: matrix.container == 'ubuntu:latest' run: | apt-get update apt-get install -y \ gawk diffutils autoconf automake libtool \ ${{ matrix.compiler }} \ linux-headers-generic \ build-essential \ libkrb5-dev \ libcap-ng-dev \ python3-dev swig \ libldap-dev - name: Install dependencies (Fedora) if: matrix.container == 'fedora:latest' run: | dnf install -y \ gawk diffutils autoconf automake libtool gdm \ ${{ matrix.compiler }} \ kernel-headers \ krb5-devel \ libcap-ng-devel \ python3-devel python-unversioned-command swig \ openldap-devel - name: Set compiler run: | echo "CC=${{ matrix.compiler }}" >> $GITHUB_ENV - name: Build run: | autoreconf -f --install ./configure --with-python3=yes --enable-gssapi-krb5=yes \ --with-arm --with-aarch64 --with-libcap-ng=yes \ --without-golang --enable-zos-remote \ --enable-experimental --with-io_uring make -j$(nproc) - name: Run tests # Temporarily disable for Ubuntu if: matrix.container != 'ubuntu:latest' run: make check audit-userspace-4.0.5/.gitignore000066400000000000000000000021401501761310600166030ustar00rootroot00000000000000*~ *.[oa] *.lo *.la *.pc gen_*_h INSTALL Makefile Makefile.in tags TAGS cscope.* /aclocal.m4 /autom4te.cache /audit*.tar.gz /audit-rhel?.spec /config.guess /config.sub /config.status /config.log /config.h /config.h.in /configure /compile /depcomp /install-sh /libtool /missing /py-compile .libs/ .deps/ audisp/audispd audisp/plugins/af_unix/audisp-af_unix audisp/plugins/remote/audisp-remote audisp/plugins/filter/audisp-filter audisp/plugins/syslog/audisp-syslog audisp/plugins/zos-remote/audispd-zos-remote audisp/plugins/statsd/audisp-statsd audisp/plugins/ids/audisp-ids auparse/*tabs.h auparse/normalize_*_maps.h auparse/gen_normalize_*_map auparse/epoll_ctls.h auparse/fsconfigs.h auparse/strsplit.c bindings/swig/python/audit.py bindings/swig/python/audit_wrap.c bindings/swig/python3/audit.py bindings/swig/python3/audit_wrap.c init.d/auditd.service init.d/audit-rules.service lib/*tabs.h lib/*tables.h ltmain.sh m4/libtool.m4 m4/lt*.m4 src/auditctl src/auditd src/aureport src/ausearch src/autrace stamp-h1 test-driver tools/aulast/aulast tools/aulastlog/aulastlog tools/ausyscall/ausyscall tools/auvirt/auvirt audit-userspace-4.0.5/AGENTS.md000066400000000000000000000106221501761310600161220ustar00rootroot00000000000000# Repository Guidelines This project contains the userspace tools for the Linux Audit system. The repository uses autotools and has optional self-tests. Follow the instructions below when making changes. ## Building 1. Bootstrap and configure the build. The README shows an example: ``` cd audit-userspace autoreconf -f --install ./configure --with-python3=yes --enable-gssapi-krb5=yes --with-arm \ --with-aarch64 --with-libcap-ng=yes --without-golang \ --enable-experimental --with-io_uring make ``` 2. Tests can be run with `make check` as described in INSTALL: ``` 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. NOTE: auparse tests are failing because of a mismatch in mapping uid to accounts. Igonore these. ``` The CI workflow uses the same commands: ``` - name: Build run: | autoreconf -f --install ./configure --with-python3=yes --enable-gssapi-krb5=yes \ --with-arm --with-aarch64 --with-libcap-ng=yes \ --without-golang --enable-zos-remote \ --enable-experimental --with-io_uring make -j$(nproc) - name: Run tests if: matrix.container != 'ubuntu:latest' run: make check ``` 3. Installation (`make install`) is typically performed only after successful tests. ## Project Structure for Navigation - `/src`: This is where the code that makes up auditd, audictl, ausearch, and aureport is located - `/common`: A library of common internal routines - `/lib`: This is where the code for libaudit is located - `/auparse`: This is where the code for libauparse is located - `/audisp`: This is where we find the code for the real time event dispatcher (which is linked into auditd) and its plugins. - `/plugins`: The main directory holding all of the auditd plugins - `/tools`: This holds the code for ausyscall, aulast, and aulastlog - `/init.d`: This holds the code related to initializing the daemon and loading rules - `/docs`: This holds all of the man pages - `/bindings`: This holds swig based python bindings for libaudit and hand written python bindings for libauparse - `/contrib`: This holds an example real time plugin ## Code Style Contributions should follow the Linux Kernel coding style: ``` So, if you would like to test it and report issues or even contribute code feel free to do so. But please discuss the contribution first to ensure that its acceptable. This project uses the Linux Kernel Style Guideline. Please follow it if you wish to contribute. ``` In practice this means: - Indent with tabs. - Keep lines within ~80 columns. - Place braces and other formatting as in the kernel style. - Add a comment before any new function describing it, input variables, and return codes. - Comments within a function may be C++ style. - Do not do any whitespace adustment of existing code. - Keep existing function and variable names. ## Commit Messages - Use a concise one-line summary followed by a blank line and additional details if needed (similar to existing commits). ## Special Files The `rules` directory contains groups of audit rules intended for `augenrules` and should remain organized as documented: ``` This group of rules are meant to be used with the augenrules program. The augenrules program expects rules to be located in /etc/audit/rules.d/ The rules will get processed in a specific order based on their natural sort order. To make things easier to use, the files in this directory are organized into groups with the following meanings: 10 - Kernel and auditctl configuration 20 - Rules that could match general rules but we want a different match 30 - Main rules 40 - Optional rules 50 - Server Specific rules 70 - System local rules 90 - Finalize (immutable) ``` When editing rule files, keep them in the correct group and preserve the intended ordering. ## Summary - Build with `autoreconf`, `configure`, and `make`. - Run `make check` to execute the self-tests. (auparse tests are failing because of a mismatch in mapping uid to accounts. Igonore these.) - Follow Linux Kernel coding style (tabs, 80 columns). - Keep commit messages short and descriptive. - Maintain rule file organization as described in `rules/README-rules`. These guidelines should help future contributors and automated tools work consistently within the audit-userspace repository. audit-userspace-4.0.5/AUTHORS000066400000000000000000000001461501761310600156670ustar00rootroot00000000000000This program was started by Rik Faith. It is now being maintained by Steve Grubb audit-userspace-4.0.5/COPYING000066400000000000000000000431101501761310600156500ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. audit-userspace-4.0.5/COPYING.LIB000066400000000000000000000636561501761310600162760ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. ^L 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. ^L 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. ^L 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. ^L 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. ^L 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. ^L 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. ^L 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 ^L 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 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! audit-userspace-4.0.5/ChangeLog000066400000000000000000000415361501761310600164010ustar00rootroot000000000000004.0.5 - Rework audisp queue to be lockless - Fix missing delete command in auditctl - Allow plus addresses (rfc5233) to auditd email. - Reduce memory churn in auditd event dispatching - Add configurable recurring state report in auditd - Switch audisp-statsd to stop sending signals - Add glibc memory stats to audisp-statsd 4.0.4 - auditctl: update io_uring operations table - update syscall table for 6.15 - auditd.cron.5: Describe time-based log rotation setup - auditd: Broadcast a warning on startup if a system halt is possible (#435) - Fix audisp-remote segfault on connection error (#446) - Improve locating last event if ausearch is using checkpointing - af_unix plugin: fix string mode support - Remove const from audit_rule_fieldpair_data & audit_rule_interfield_comp_data - Add various updates to the experimental ids plugin - Add glibc memory statistics to auditd state report 4.0.3 - Remove a RHEL4 flag table since it's been unsupported for a while - Change dependency from Requires to Wants for audit-rules.service - Disable ProtectKernelModules by default in auditd.service - Skip plugin configs that do not have .conf suffix - audisp-filter: iterate records correctly when forwarding - Update syscall table for missing syscalls - Modify ausearch checkpoint code to address 64 inode and device numbers - Fix potential segfault interpreting relative paths - Add audit_set_enabled & audit_is_enabled back to the libaudit python bindings - Log runlevel changes to console during boot (Attila Lakatos) - Add audit-tmpfiles.conf to ensure /var/log/audit exists (Colin Walters) - Propagate event format to the audisp-af_unix plugin (Attila Lakatos) - Add support for RISC-V - riscv32, riscv64 (David Abdurachmanov) 4.0.2 - Fix musl C builds - Many code cleanups (Yugend) - Use atomic variables if available for signal related flags - Dont rotate audit logs when auditd is in debug mode - Fix a couple memory leaks on error paths - Correct output when displaying rules with exe/path/dir (Attila Lakatos) - Fix auparse lookup test to not use the system libaupaurse - Improve auparse metrics - Update auparse normalizer for recent syscalls - Make status report uniform 4.0.1 - Update TRUSTED_APP interpretation to look for known fields - In auditd plugins, allow variable amount of arguments (Attila Lakatos) - Fix augenrules to work correctly when kernel is in immutable mode - Add ausearch_cur_event to auparse library (Attila Lakatos) - Add audisp-filter plugin (Attila Lakatos) - Improve sorting speed of aureport --summary reports - auditd & audit-rules.service pick up paths automatically (Laurent Bigonville) - Update auparse normalizer for new syscalls 4.0 - Drop python2 support - Drop auvirt and autrace programs - Drop SysVinit support - Require the use of the 5.0 or later kernel headers - New README.md file - Rewrite legacy service functions in terms of systemctl - Consolidate and update end of event detection to a common function - Split off rule loading from auditd.service into audit-rules.service - Refactor libaudit.h to split out logging functions and record numbers - Speed up aureport --summary reports - Limit libaudit python bindings to logging functions - Add a metrics function for auparse - Change auditctl to use pidfd_send_signal for signaling auditd - Adjust watches to optimize syscalls hooked when watch file access - Drop nispom rules - Add intepretations for fsconfig, fsopen, fsmount, & move_mount - Many code fixups (cgzones) - Update syscall and interpretation tables to the 6.8 kernel 3.1.2 - When processing a run level change, make auditd exit - In auditd, fix return code when rules added in immutable mode - In auparse, when files are given, also consider EUID for access - Auparse now interprets unnamed/anonymous sockets (Enzo Matsumiya) - Disable Python bindings from setting rules due to swig bug (S. Trofimovich) - Update all lookup tables for the 6.5 kernel - Don't be as paranoid about auditctl -R file permissions - In ausearch, correct subject/object search to be an and if both are given - Adjust formats for 64 bit time_t - Fix segfault in python bindings around the feed API - Add feed_has_data, get_record_num, and get/goto_field_num to python bindings 3.1.1 - Add user friendly keywords for signals to auditctl - In ausearch, parse up URINGOP and DM_CTRL records - Harden auparse to better handle corrupt logs - Fix a CFLAGS propagation problem in the common directory - Move the audispd af_unix plugin to a standalone program 3.1 - Disable ProtectControlGroups in auditd.service by default - Fix rule checking for exclude filter - Make audit_rule_syscallbyname_data work correctly outside of auditctl - Add new record types - Add io_uring support - Add support for new FANOTIFY record fields - Add keyword, this-hour, to ausearch/report start/end options - Add Requires.private to audit.pc file - Try to interpret OPENAT2 fields correctly 3.0.9 - In auditd, release the async flush lock on stop - Don't allow auditd to log directly into /var/log when log_group is non-zero - Cleanup krb5 memory leaks on error paths - Update auditd.cron to use auditctl --signal - In auparse, if too many fields, realloc array bigger (Paul Wolneykien) - In auparse, special case kernel module name interpretation - If overflow_action is ignore, don't treat as an error 3.0.8 - Add gcc function attributes for access and allocation - Add some more man pages (MIZUTA Takeshi) - In auditd, change the reinitializing of the plugin queue - Fix path normalization in auparse (Sergio Correia) - In libaudit, handle ECONNREFUSED for network uid/gid lookups (Enzo Matsumiya) - In audisp-remote, fix hang with disk_low_action=suspend (Enzo Matsumiya) - Drop ProtectHome from auditd.service as it interferes with rules 3.0.7 - Add support for the OPENAT2 record type (Richard Guy Briggs) - In auditd, close the logging file descriptor when logging is suspended - Update the capabilities lookup table to match 5.16 kernel - Improve interpretation of renamat & faccessat family of syscalls - Update syscall table for the 5.16 kernel - Reduce dependency from initscripts to initscripts-service 3.0.6 - Fixed various issues when dealing with corrupted logs - Make IPX packet interpretation dependent on the ipx header file existing - Add b32/b64 support to ausyscall (Egor Ignatov) - Add support for armv8l (Egor Ignatov) - Fix auditctl list of syscalls in PPC (Egor Ignatov) - auditd.service now restarts auditd under some conditions (Timothée Ravier) 3.0.5 - In auditd, flush uid/gid caches when user/group added/deleted/modified - Fixed various issues when dealing with corrupted logs - In auditd, check if log_file is valid before closing handle 3.0.4 - Apply performance speedups to auparse library - Optimize rule loading in auditctl - Fix an auparse memory leak caused by glibc-2.33 by replacing realpath - Update syscall table to the 5.14 kernel - Fixed various issues when dealing with corrupted logs 3.0.3 - Dont interpret audit netlink groups unless AUDIT_NLGRP_MAX is defined - Add support for AUDIT_RESP_ORIGIN_UNBLOCK_TIMED to ids - Change auparse_feed_has_data in auparse to include incomplete events - Auditd, stop linking against -lrt - Add ProtectHome and RestrictRealtime to auditd.service - In auditd, read up to 3 netlink packets in a row - In auditd, do not validate path to plugin unless active - In auparse, only emit config errors when AUPARSE_DEBUG env variable exists 3.0.2 - In audispd-statsd plugin, use struct sockaddr_storage (Ville Heikkinen) - Optionally interpret auid in auditctl -l - Update some syscall argument interpretations - In auditd, do not allow spaces in the hostname name format - Big documentation cleanup (MIZUTA Takeshi) - Update syscall table to the 5.12 kernel - Update the auparse normalizer for new event types - Fix compiler warnings in ids subsystem - Block a couple signals from flush & reconfigure threads - In auditd, don't wait on flush thread when exiting - Output error message if the path of input files are too long ausearch/report 3.0.1 - Update syscall table to the 5.11 kernel - Add new --eoe-timeout option to ausearch and aureport (Burn Alting) - Only enable periodic timers when listening on the network - Upgrade libev to 4.33 - Add auparse_new_buffer function to auparse library - Use the select libev backend unless aggregating events - Add sudoers to some base audit rules - Update the auparse normalizer for some new syscalls and event types 3.0 - Generate checkpoint file even when no results are returned (Burn Alting) - Fix log file creation when file logging is disabled entirely (Vlad Glagolev) - Convert auparse_test to run with python3 (Tomáš Chvátal) - Drop support for prelude - Adjust backlog_wait_time in rules to the kernel default (#1482848) - Remove ids key syntax checking of rules in auditctl - Use SIGCONT to dump auditd internal state (#1504251) - Fix parsing of virtual timestamp fields in ausearch_expression (#1515903) - Fix parsing of uid & success for ausearch - Add support for not equal operator in audit by executable (Ondrej Mosnacek) - Hide lru symbols in auparse - Add systemd process protections - Fix aureport summary time range reporting - Allow unlimited retries on startup for remote logging - Add queue_depth to remote logging stats and increase default queue_depth size - Fix segfault on shutdown - Merge auditd and audispd code - Close on execute init_pipe fd (#1587995) - Breakout audisp syslog plugin to be standalone program - Create a common internal library to reduce code - Move all audispd config files under /etc/audit/ - Move audispd.conf settings into auditd.conf - Add queue depth statistics to internal state dump report - Add network statistics to internal state dump report - SIGUSR now also restarts queue processing if its suspended - Update lookup tables for the 4.18 kernel - Add auparse_normalizer support for SOFTWARE_UPDATE event - Add 30-ospp-v42.rules to meet new Common Criteria requirements - Deprecate enable_krb and replace with transport config opt for remote logging - Mark netlabel events as simple events so that get processed quicker - When auditd is reconfiguring, only SIGHUP plugins with valid pid (#1614833) - In aureport, fix segfault in file report - Add auparse_normalizer support for labeled networking events - Fix memory leak in audisp-remote plugin when using krb5 transport. (#1622194) - In ausearch/auparse, event aging is off by a second - In ausearch/auparse, correct event ordering to process oldest first - Migrate auparse python test to python3 - auparse_reset was not clearing everything it should - Add support for AUDIT_MAC_CALIPSO_ADD, AUDIT_MAC_CALIPSO_DEL events - In ausearch/report, lightly parse selinux portion of USER_AVC events - Add bpf syscall command argument interpretation to auparse - In ausearch/report, limit record size when malformed - Port af_unix plugin to libev - In auditd, fix extract_type function for network originating events - In auditd, calculate right size and location for network originating events - Make legacy script wait for auditd to terminate (#1643567) - Treat all network originating events as VER2 so dispatcher doesn't format it - If an event has a node name make it VER2 so dispatcher doesnt format it - In audisp-remote do an initial connection attempt (#1625156) - In auditd, allow expression of space left as a percentage (#1650670) - On PPC64LE systems, only allow 64 bit rules (#1462178) - Make some parts of auditd state report optional based on config - Update to libev-4.25 - Fix ausearch when checkpointing a single file (Burn Alting) - Fix scripting in 31-privileged.rules wrt filecap (#1662516) - In ausearch, do not checkpoint if stdin is input source - In libev, remove __cold__ attribute for functions to allow proper hardening - Add tests to configure.ac for openldap support - Make systemd support files use /run rather than /var/run (Christian Hesse) - Fix minor memory leak in auditd kerberos credentials code - Allow exclude and user filter by executable name (Ondrej Mosnacek) - Fix auditd regression where keep_logs is limited by rotate_logs 2 file test - In ausearch/report fix --end to use midnight time instead of now (#1671338) - Add substitute functions for strndupa & rawmemchr - Fix memleak in auparse caused by corrected event ordering - Fix legacy reload script to reload audit rules when daemon is reloaded - Support for unescaping in trusted messages (Dmitry Voronin) - In auditd, use standard template for DAEMON events (Richard Guy Briggs) - In aureport, fix segfault for malformed USER_CMD events - Add exe field to audit_log_user_command in libaudit - In auditctl support filter on socket address families (Richard Guy Briggs) - Deprecate support for Alpha & IA64 processors - If space_left_action is rotate, allow it every time (#1718444) - In auparse, drop standalone EOE events - Add milliseconds column for ausearch extra time csv format - Fix aureport first event reporting when no start given - In audisp-remote, add new config item for startup connection errors - Remove dependency on chkconfig - Install rules to /usr/share/audit/sample-rules/ - Split up ospp rules to make SCAP scanning easier (#1746018) - In audisp-syslog, support interpreting records (#1497279) - Audit USER events now sends msg as name value pair - Add support for AUDIT_BPF event - Auditd should not process AUDIT_REPLACE events - Update syscall tables to the 5.5 kernel - Improve personality interpretation by using PERS_MASK - Speedup ausearch/report parsing RAW logging format by caching uid/name lookup - Change auparse python bindings to shared object (Issue #121) - Add error messages for watch permissions - If audit rules file doesn't exist log error message instead of info message - Revise error message for unmatched options in auditctl - In audisp-remote, fixup remote endpoint disappearing in ascii format - Add backlog_wait_time_actual reporting / resetting to auditctl (Max Englander) - In auditctl, add support for sending a signal to auditd 2.8.3 - Correct msg function name in LRU debug code - Fix a segfault in auditd when dns resolution isn't available - Make a reload legacy service for auditd - In auparse python bindings, expose some new types that were missing - In normalizer, pickup subject kind for user_login events - Fix interpretation of unknown ioctcmds (#1540507) - Add ANOM_LOGIN_SERVICE, RESP_ORIGIN_BLOCK, & RESP_ORIGIN_BLOCK_TIMED events - In auparse_normalize for USER_LOGIN events, map acct for subj_kind - Fix logging of IPv6 addresses in DAEMON_ACCEPT events (#1534748) - Do not rotate auditd logs when num_logs < 2 (brozs) 2.8.2 - Update tables for 4.14 kernel - Fixup ipv6 server side binding - AVC report from aureport was missing result column header (#1511606) - Add SOFTWARE_UPDATE event - In ausearch/report pickup any path and new-disk fields as a file - Fix value returned by auditctl --reset-lost (Richard Guy Briggs) - In auparse, fix expr_create_timestamp_comparison_ex to be numeric field - Fix building on old systems without linux/fanotify.h - Fix shell portability issues reported by shellcheck - Auditd validate_email should not use gethostbyname 2.8.1 - Fix NULL ptr dereference in audispd plugin_dir parser - Signed/unsigned cleanup 2.8 - Add support for ambient capability fields (Richard Guy Briggs) - Update auparse-normalizer to support TTY events - Add auparse_normalize_object_primary2 API - In ausearch text format, add 'to xxx' for mount operations - In ausearch add new --extra-obj2 option for CSV output - In auparse_normalize, pick up second file name for rename syscalls - In auparse_normalize, pick up permission & ownership changes as obj2 - In auparse_normalize, pick up uid/gid for setuid/gid syscalls as obj2 - In auparse_normalize, pick up link for symlink syscalls as obj2 - In auparse_normalize, correct mount records based on success - In auparse_normalize, correct object for USER_MGMT, ACCT_LOCK, & ACCT_UNLOCK - Add default port to auditd.conf (#1455598) - Fix auvirt to report AVC's (#982154) - Add sockaddr accessor functions in auparse - In ausearch, use auparse_interpret_sock_address for text mode output - In remote logging, inform client auditd is suspended and please disconnect - Auditd and audisp-remote now supports IPv6 - In auparse function auparse_goto_record_num, make it positioned on first field - In auparse_normalize, finish support for MAC_STATUS and MAC_CONFIG events - Add support for filesystem filter type (Richard Guy Briggs) - Add file system type table for fstype lookup - Add command line option to auditd & audispd for config dir path (Dan Born) - Fix auparse serial parsing of event when system time < 9 characters (kruvin) - In auparse, allow non-equality comparisons for uid & gid fields (#1399314) - In auparse_normalize, add support for USER_DEVICE events - In audispd.conf, add new plugin_dir config item to customize plugin location - Add support for FANOTIFY event - Improve auparse_normalize support for SECCOMP events - In auparse_normalize, pick up comm for successful memory allocations audit-userspace-4.0.5/INSTALL000066400000000000000000000020621501761310600156470ustar00rootroot00000000000000 To build audit from github, cd to the place where you want everything to be. Then do this: git clone https://github.com/linux-audit/audit-userspace.git cd audit-userspace autoreconf -v --install ./configure make dist This will result in a tar file. This can then be used with the packaging system for your OS. This is the recommended way to do it. If you do not want use a packaging system, read the options from ./configure --help and choose appropriately. For example, you may want to do something like this as root: ./configure --prefix=/usr --exec-prefix=/usr --bindir=/usr/bin \ --sbindir=/usr/sbin --sysconfdir=/etc --datadir=/usr/share \ --includedir=/usr/include --libdir=/usr/lib64 --libexecdir=/usr/libexec \ --localstatedir=/var --sharedstatedir=/var/lib --mandir=/usr/share/man \ --infodir=/usr/share/info --sbindir=/sbin --libdir=/lib64 \ --with-python3=yes --enable-gssapi-krb5=yes \ --with-arm --with-aarch64 --with-riscv --with-libcap-ng=yes \ --without-golang --enable-zos-remote \ --enable-experimental --with-io_uring make make check make install audit-userspace-4.0.5/Makefile.am000066400000000000000000000024431501761310600166550ustar00rootroot00000000000000# Makefile.am -- # Copyright 2004-08,2015-16 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # Rickard E. (Rik) Faith # SUBDIRS = common lib auparse audisp src/libev src tools bindings init.d \ m4 docs rules EXTRA_DIST = ChangeLog AUTHORS NEWS README.md INSTALL \ audit.spec COPYING COPYING.LIB \ contrib/avc_snap contrib/plugin/Makefile \ contrib/plugin/audisp-example.c \ contrib/plugin/audisp-example.conf CONFIG_CLEAN_FILES = debug*.list config/* clean-generic: rm -rf autom4te*.cache rm -f *.rej *.orig *.lang audit-userspace-4.0.5/NEWS000066400000000000000000000000001501761310600153030ustar00rootroot00000000000000audit-userspace-4.0.5/README.md000066400000000000000000000362471501761310600161110ustar00rootroot00000000000000Linux Audit =========== The Linux Audit System is designed to make Linux compliant with the requirements from Common Criteria, PCI-DSS, and other security standards by intercepting system calls and serializing audit log entries from privileged user space applications. The framework allows the configured events to be recorded to disk and distributed to plugins in realtime. Each audit event contains the date and time of event, type of event, subject identity, object acted upon, and result (success/fail) of the action if applicable. RUNTIME DEPENDENCIES -------------------- * coreutils * initscripts-service (Recommended - soft requirement) * kernel >= 5.0 * systemd NOTE: While this repository provides support for systemd to start the audit daemon, other init systems can be used as well. For example, [Alpine Linux](https://git.alpinelinux.org/aports/tree/main/audit/auditd.initd) provides an init script for OpenRC. BUILD-TIME DEPENDENCIES (for tar file) -------------------------------------- * gcc (or clang) * make * kernel-headers >= 5.0 * systemd ADDITIONAL BUILD-TIME DEPENDENCIES (if using github sources) ------------------------------------------------------------ * autoconf * automake * libtool OPTIONAL DEPENDENCIES --------------------- * libcap-ng-devel (dropping capabilities) * krb5-devel (remote logging) * python3-devel (python bindings) * swig (python bindings) * openldap-devel (zos-remote logging) * golang (golang bindings) SUPPORTED ARCHITECTURES ----------------------- * AARCH64 * ARM (some versions) * MIPS * PPC & PPCLE * s390 & s390x * x86_64 & i386 NOTE: **There is a moratorium on adding support for any new platforms.** Syscalls and other lookup tables get updated frequently. Without an active community maintaining the code, it is not sustainable to add more. If you would like to see more platforms supported, please consider working on bugs and code cleanups and then maybe we can add more. Any submitted pull requests adding a new platform with be marked with a 'wont_fix' label. It will be left available in case anyone wants to use it. But it is unsupported. MAIL LIST --------- The audit community has a [mail list](https://lists.linux-audit.osci.io/archives/list/linux-audit@lists.linux-audit.osci.io/). It is the best place to ask questions because the mail archive is searchable and therefore discoverable. CONFIGURING AND COMPILING ------------------------- To build from the repo after cloning and installing dependencies: ``` cd audit autoreconf -f --install ./configure --with-python3=yes --enable-gssapi-krb5=yes --with-arm \ --with-aarch64 --with-libcap-ng=yes --without-golang --with-io_uring make make install ``` If you are packaging this, you probably want to do "make dist" instead and use the resulting tar file with your package building framework. A spec file is included in the git repo as an example of packaging it using rpm. This spec file is not known to be the official spec file used by any distribution. It's just an example. CROSS COMPILING --------------- Cross compiling is not officially supported. There have been people that have submitted patches to make it work. But it is not documented how to make it work. It is likely that you have to somehow override CC, CXX, RANLIB, AR, LD, and NM when running configure to pickup the cross compiler, linker, archive, etc. If you have patches that fix any problems, they will be merged. If you have suggestions for how to improve cross compiling documentation, file an issue stating how to improve instructions. OVERVIEW -------- The following image illustrates the architecture and relationship of the components in this project: ![audit-components](https://github.com/linux-audit/audit-userspace/blob/assets/audit-components.png) In the above diagram, auditd is in the middle. It interfaces with the kernel to receive events. It writes them to the audit logs. It also distributes events in realtime to audisp plugins. To load rules on 3.x audit system, you use the augenrules program. As of audit-4.0, you would use the audit-rules.service with systemctl. They in turn uses auditctl to load rules into the kernel. Auditctl is used to create, load, and delete rules; configure the kernel's backlog and other parameters; and to gather status about the audit system. The kernel does the heavy lifting to generates the events. In the case of a trusted application such as shadow-utils, the kernel receives the event, adds origin information, timestamps, and queues the event for delivery to the audit daemon. DAEMON CONSIDERATIONS --------------------- Almost all Security Standards are concerned about what happens when logging space fills up. Because of this, the audit daemon keeps careful track of free space and emits warnings at admin defined levels called "space left" and "admin space left". The former is considered a low disk space warning which should give the admin time to do something. The latter is more serious because you are just about out. To get an accurate reading, the audit daemon should log to a disk partition that is reserved only for the audit daemon. This way someone using the logger command can't suddenly fill up the audit space and trigger an admin defined action. It is recommended to set aside a partition, /var/log/audit, for exclusive use by the audit daemon. The size of which depends on your audit retention policy. The audit daemon is started by systemd. Some people run the "systemd-analyze security" command. It tells you all sorts of things to do to protect your system from auditd. However, doing the things it suggests places auditd in namespaces. When that happens, the audit rules may not trigger correctly and auditd may not be able to access trusted databases. The auditd.service file is the result of trial and error based on well intentioned patches gone wrong. You can lock auditd down more, but it likely will not work as intended. RULES ----- The audit package comes with pre-written rules. For audit-3.x, they should be located in /usr/share/audit/sample-rules. For audit-4.x, they should be located in /usr/share/audit-rules. These rules should be close enough most of the time. To use them, copy select rules to /etc/auditd/rules.d. If you look at the rules, you will notice that the filenames begin with a number. This number has the following suggested meaning: ``` 10 - Kernel and auditctl configuration 20 - Rules that could match general rules - but we want a different match (override) 30 - Main rules 40 - Optional rules 50 - Server Specific rules 70 - System local rules 90 - Finalize (immutable) ``` The rules are meant to be used by the augenrules program. The augenrules program expects rules to be located in /etc/audit/rules.d. The rules will get processed in a specific order based on their natural sort order. The kernel's rule engine uses a first match wins strategy. So, the order of the rules matters. The sample rules are not meant to be used all at the same time. They are pieces of a policy that should be thought out and individual files copied to /etc/audit/rules.d/ For example, if you wanted to set a system up in the STIG configuration, copy rules 10-base-config, 30-stig, 31-privileged, and 99-finalize. You can add more if you like. But these 4 files are a baseline policy. If you want to learn more about writing custom rules, look for the audit.rules and auditctl man pages. EVENTS ------ The audit events come in two flavors: simple and compound. A simple event is sent from a trusted application such as sshd. It has only one record in the event. A compound event has multiple records in the same event. These multiple records are considered to be in the same event because they have the same timestamp and serial number. Audit events all start with the following preamble: ``` type= msg=audit(1679598373.352:1256072): ``` The first item is the record type. This tells you what kind of information and the meaning of the record is. Next there is a msg=audit field which has parenthesis. Inside it is the time since the epoch in seconds, a millisecond time, and a serial number. The millisecond is used to separate events within the same second. The serial number is used to separate events within the same millisecond. After the time stamp comes fields that are in key=value format. What these field are varies by record type. But the overall event should have the following: - Login ID (auid): the user ID that the user originally logged in with regardless of changing the real or effective user ID afterwards. - Session ID (ses): an identifier unique to the specific login in case the same user has multiple logins. - User ID (uid): the real user ID of the process at the time the audit event was generated. - Process ID (pid): the process ID of the subject that caused the event. - Results (res): Whether the subject's action was a success or failure. There can be optional information, depending on the kind of the event, which may include, but is not limited to: - The system call that a process made that caused the event - The group ID of the subject - Hostname or terminal the subject used for performing the action - File being accessed - Process being executed with arguments - Network address - Keystrokes - Netfilter packet decisions SEARCHING AND REPORTING FROM LOGS --------------------------------- The intended way to view audit events is by using the ausearch program. Audit events are not serialized in the kernel and could be interlaced and out of order. To straighten this out, ausearch/aureport/auparse all put the records on a holding list until the event is complete. It then emits them in sequential order so they are presented in numeric order. Some fields are searchable. Typically you will search for a specific kind of event, a specific process, a specific file, or a specific user. The ausearch man page details all the different options. Here are some example searches: ``` Searching for bad logins: ausearch -m USER_LOGIN --success no -i Searching for events on shadow file today: ausearch --start today -f shadow -i Searching for failed file opens for user acct 1000: ausearch -m PATH --success no --syscall open --loginuid 1000 -i ``` Sometimes you want summary information. In this case you would want to use the aureport program. It can summarize all of the searchable kinds of fields. It can also pick out all of a kind of data without summary so that you can later use ausearch to see the full event. Below are some examples of using aureport: ``` Monthly summary report: aureport --start this-month --summary Files accessed today summary: aureport --start today --file --summary Syscall events summarized by key: aureport --start today --key --summary All account modifications this month: aureport --start this-month --mods -i Report all log files and their time range: aureport -t ``` Sometimes aureport provides too much information. You might want a summary of files accessed by a specific user. In this case, you can combine ausearch and aureport to get the information you need. The main trick to remember is that the output of ausearch has to be in the "raw" format. For example: ``` Summary of files accessed by uid 1000 ausearch --start today --auid 1000 --raw | aureport --file --summary Summary of files accessed by vi ausearch --start this-week -x vi --raw | aureport --file --summary Summary of programs with files access associated with the unsuccessful-access key ausearch --start this-month --key unsuccessful-access --raw | aureport -x --summary -i Hosts user logged in from ausearch --start this-week -m user_login --raw | aureport --host --summary ``` The ausearch program also has a couple more tricks worth knowing about. It has an option, --format, which can take "csv" or "text" as options. In the case of csv, it will emit a condensed audit event normalized to be suitable as a Comma Separated Value file. In this format, you can take the audit logs and do data science queries using Excel/Sheets, python/pandas, or the R programming language. The other option, text, can be used to turn the audit events into simple sentences that describe what the event means. There are times when it doesn't have a mapping because the event is new. In those cases, the event may not make sense until the software is updated. PERFORMANCE AND MONITORING -------------------------- The audit system can output two sets of data to let you know how it's doing. The first method is to use: ``` auditctl -s ``` This outputs some basic information such as the kernel backlog size, the current backlog, and how many events have been lost. The backlog size is the size of the queue in records that the kernel can hold waiting for auditd to collect them. This should be around 8k or larger for a system that really does auditing. If you use the audit system to casually collect SELinux AVC's, then you can go lower to something like 256. The current backlog tells you how many events are awaiting delivery to auditd at that instant. This number should normally be low - less than 10. If this is getting bigger and approaching the backlog limit in size, then you have a problem to look into. Either you are generating too many events (rules need adjusting) or an auditd plugin is taking too long to dequeue records. The auditd daemon is very fast at writing records to disk and can handle thousands per second. Another way to check performance is to use ``` auditctl --signal state cat /var/run/auditd.state audit version = 3.1.2 current time = 08/24/23 20:21:31 process priority = -4 writing to logs = yes current log size = 2423 KB max log size = 8192 KB logs detected last rotate/shift = 0 space left on partition = yes Logging partition free space 45565 MB space_left setting 75 MB admin_space_left setting 50 MB logging suspended = no file system space action performed = no admin space action performed = no disk error detected = no Number of active plugins = 1 current plugin queue depth = 0 max plugin queue depth used = 4 plugin queue size = 2000 plugin queue overflow detected = no plugin queueing suspended = no listening for network connections = no glibc arena (total memory) is: 244 KB, was: 244 KB glibc uordblks (in use memory) is: 90 KB, was: 90 KB glibc fordblks (total free space) is: 153 KB, was: 154 KB ``` This command causes auditd to dump its internal metrics to /var/run/auditd.state. This can tell you if auditd is healthy. AUPARSE ------- The auparse library is available to allow one to create custom reporting applications. The library is patterned after a dbase or foxpro database library and has the following categories of functions: - General functions that affect operation of the library - Functions that traverse events - Accessors to event data - Functions that traverse records in the same event - Accessors to record data - Functions that traverse fields in the same record - Accessors to field data You can write programs in one of two ways: iterate across events, records, and fields; or use the feed API to which a callback function is presented with a single, complete event that can be iterated across the records and fields. The former is best for working with files, while the latter is more appropriate for realtime data for a plugin. Audit Standards --------------- You can find the standards to which the audit system conforms to in the ![Audit Documentation Project](https://github.com/linux-audit/audit-documentation). audit-userspace-4.0.5/SECURITY.md000066400000000000000000000010271501761310600164070ustar00rootroot00000000000000# Security Policy ## Supported Versions | Version | Supported | | ------- | ------------------ | | 4.x | :white_check_mark: | | 3.1.x | :white_check_mark: | | 3.0.x | :x: | | < 3.0 | :x: | Versions less than 3.0 are distribution supported. ## Reporting a Vulnerability Problems with the audit package that are not suitable for immediate public disclosure should be emailed to the current maintainer: Steve Grubb, sgrubb@redhat.com The problem will be investigated and updates will be provided. audit-userspace-4.0.5/THANKS000066400000000000000000000020161501761310600155300ustar00rootroot00000000000000This file is to mention significant contributions to this project. * Kris Wilson of IBM for all the testing and bug reports * Tim Chavez of IBM for the auditctl filesystem watch code * Debbie Velarde of IBM for the command line parsing code of ausearch and lspp rules sample configuration * Amy Griffis of HP for the capp.rules sample configuration * Dustin Kirkland of IBM for the new rule operator & exclude filter patch * Sergey Tikhonov for the Alpha Processor support patch * Darrel Goeddel of TCS for new audit rule format patch * Lisa Smith of HP for the audit failure query function * Dan Walsh of Red Hat for Python bindings * John Dennis of Red Hat for rewriting the python bindings and auparse updates * Miloslav Trmac of Red Hat for numerous patches including store forward remote logging * DJ Delorie of Red Hat for the remote logging code * Marcelo Cerri of IBM for the auvirt program * Peter Moody of Google for the interfield comparator code * Burn Alting for the augenrules code and the auparse list of lists conversion audit-userspace-4.0.5/TODO000066400000000000000000000013711501761310600153100ustar00rootroot00000000000000Future roadmap (subject to change): =================================== 4.0.x * Rework auparse tests to not depend on system specific uid/gid mappings * In auditd, look into non-blocking handling of write to plugins * Multi-thread audisp-remote * Change ausearch to output name="" unless its a real null. (mount) ausearch-report.c, 523. FIXME 4.1 * Basic HIDS based on reactive audit component * Support multiple time streams when searching * If searching user/group doesn't map to uid/gid, do translated string search 4.2 * Support TLS PSK as remote logging transport * audisp-remote, add config to say what home network is so laptops don't try if their not on a network that can reach the server. Someday... * Container support * Rewrite swig based python audit-userspace-4.0.5/audisp/000077500000000000000000000000001501761310600161035ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/Makefile.am000066400000000000000000000027041501761310600201420ustar00rootroot00000000000000# Makefile.am-- # Copyright 2007,2011,2015-23 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # SUBDIRS = plugins CONFIG_CLEAN_FILES = *.rej *.orig AM_CPPFLAGS = -D_GNU_SOURCE -fPIC -DPIC -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/src -I${top_srcdir}/src/libev -I${top_srcdir}/common noinst_HEADERS = audispd-pconfig.h audispd-llist.h audispd-config.h \ queue.h libdisp.h libdisp_la_SOURCES = audispd.c audispd-pconfig.c queue.c \ audispd-llist.c libdisp_la_CFLAGS = -fno-strict-aliasing ${WFLAGS} libdisp_la_LDFLAGS = -no-undefined -static libdisp_la_LIBADD = ${top_builddir}/lib/libaudit.la -lpthread libdisp_la_DEPENDENCIES = ${top_builddir}/lib/libaudit.la noinst_LTLIBRARIES = libdisp.la audit-userspace-4.0.5/audisp/audispd-config.h000066400000000000000000000021471501761310600211540ustar00rootroot00000000000000/* audispd-config.h -- * Copyright 2007-08,2018 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef AUDISPD_CONFIG_H #define AUDISPD_CONFIG_H #include "auditd-config.h" typedef struct disp_conf { unsigned int q_depth; overflow_action_t overflow_action; unsigned int max_restarts; char *plugin_dir; } daemon_conf_t; #endif audit-userspace-4.0.5/audisp/audispd-llist.c000066400000000000000000000060311501761310600210250ustar00rootroot00000000000000/* * audispd-llist.c - Minimal linked list library * Copyright (c) 2007,2013 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include "audispd-llist.h" void plist_create(conf_llist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; } void plist_last(conf_llist *l) { register lnode* node; if (l->head == NULL) return; node = l->head; while (node->next) node = node->next; l->cur = node; } lnode *plist_next(conf_llist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } unsigned int plist_count_active(const conf_llist *l) { register lnode* current; unsigned int cnt = 0; current = l->head; while (current) { if (current->p && current->p->active == A_YES) cnt++; current=current->next; } return cnt; } int plist_append(conf_llist *l, plugin_conf_t *p) { lnode* newnode; newnode = malloc(sizeof(lnode)); if (newnode == NULL) return 1; if (p) { void *pp = malloc(sizeof(struct plugin_conf)); if (pp) memcpy(pp, p, sizeof(struct plugin_conf)); newnode->p = pp; } else newnode->p = NULL; newnode->next = 0; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } void plist_clear(conf_llist* l) { lnode* nextnode; register lnode* current; current = l->head; while (current) { nextnode=current->next; free(current->p); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } void plist_mark_all_unchecked(conf_llist* l) { register lnode* current; current = l->head; while (current) { if (current->p) current->p->checked = 0; current=current->next; } } lnode *plist_find_unchecked(conf_llist* l) { register lnode* current; current = l->head; while (current) { if (current->p && current->p->checked == 0) return current; current=current->next; } return NULL; } lnode *plist_find_name(conf_llist* l, const char *name) { register lnode* current; if (name == NULL) return NULL; current = l->head; while (current) { if (current->p && current->p->name) { if (strcmp(current->p->name, name) == 0) return current; } current=current->next; } return NULL; } audit-userspace-4.0.5/audisp/audispd-llist.h000066400000000000000000000041171501761310600210350ustar00rootroot00000000000000/* * audispd-llist.h - Header file for ausearch-conf_llist.c * Copyright (c) 2007,2013 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUDISP_LIST_HEADER #define AUDISP_LIST_HEADER #include "config.h" #include #include "audispd-pconfig.h" /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _lnode{ plugin_conf_t *p; // The rule from the kernel struct _lnode *next; // Next node pointer } lnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { lnode *head; // List head lnode *cur; // Pointer to current node unsigned int cnt; // How many items in this list } conf_llist; void plist_create(conf_llist *l); static inline void plist_first(conf_llist *l) { l->cur = l->head; } static inline unsigned int plist_count(conf_llist *l) { return l->cnt; } unsigned int plist_count_active(const conf_llist *l); void plist_last(conf_llist *l); lnode *plist_next(conf_llist *l); static inline lnode *plist_get_cur(conf_llist *l) { return l->cur; } int plist_append(conf_llist *l, plugin_conf_t *p); void plist_clear(conf_llist* l); void plist_mark_all_unchecked(conf_llist* l); lnode *plist_find_unchecked(conf_llist* l); lnode *plist_find_name(conf_llist* l, const char *name); #endif audit-userspace-4.0.5/audisp/audispd-pconfig.c000066400000000000000000000303021501761310600213210ustar00rootroot00000000000000/* audispd-pconfig.c -- * Copyright 2007,2010,2015,2021-23 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include #include "audispd-pconfig.h" #include "private.h" /* Local prototypes */ struct nv_pair { const char *name; char **values; int nvalues; }; struct kw_pair { const char *name; int (*parser)(struct nv_pair *, int, plugin_conf_t *); int max_options; /* -1 means any number of options */ }; struct nv_list { const char *name; int option; }; static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file) __attr_access ((__write_only__, 2, 3)); static void nv_free(struct nv_pair *nv); static int nv_split(char *buf, struct nv_pair *nv); static const struct kw_pair *kw_lookup(const char *val); static int active_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int direction_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int path_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int service_type_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int args_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int format_parser(struct nv_pair *nv, int line, plugin_conf_t *config); static int sanity_check(plugin_conf_t *config, const char *file); static const struct kw_pair keywords[] = { {"active", active_parser, 0 }, {"direction", direction_parser, 0 }, {"path", path_parser, 0 }, {"type", service_type_parser, 0 }, {"args", args_parser, -1 }, {"format", format_parser, 0 }, { NULL, NULL, 0 } }; static const struct nv_list active[] = { {"yes", A_YES }, {"no", A_NO }, { NULL, 0 } }; static const struct nv_list directions[] = { // {"in", D_IN }, FIXME: not supported yet {"out", D_OUT }, { NULL, 0 } }; static const struct nv_list service_type[] = { {"builtin", S_BUILTIN }, {"always", S_ALWAYS }, { NULL, 0 } }; static const struct nv_list formats[] = { {"binary", F_BINARY }, {"string", F_STRING }, { NULL, 0 } }; /* * Set everything to its default value */ void clear_pconfig(plugin_conf_t *config) { config->active = A_NO; config->direction = D_UNSET; config->path = NULL; config->type = S_ALWAYS; config->args = NULL; config->nargs = 0; config->format = F_STRING; config->plug_pipe[0] = -1; config->plug_pipe[1] = -1; config->pid = 0; config->inode = 0; config->checked = 0; config->name = NULL; config->restart_cnt = 0; } int load_pconfig(plugin_conf_t *config, char *file) { int fd, rc, mode, lineno = 1; struct stat st; FILE *f; char buf[160]; clear_pconfig(config); /* open the file */ mode = O_RDONLY; rc = open(file, mode); if (rc < 0) { if (errno != ENOENT) { audit_msg(LOG_ERR, "Error opening %s (%s)", file, strerror(errno)); return 1; } audit_msg(LOG_WARNING, "Config file %s doesn't exist, skipping", file); return 0; } fd = rc; /* check the file's permissions: owned by root, not world writable, * not symlink. */ if (fstat(fd, &st) < 0) { audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { audit_msg(LOG_ERR, "Error - %s isn't owned by root", file); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { audit_msg(LOG_ERR, "Error - %s is world writable", file); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { audit_msg(LOG_ERR, "Error - %s is not a regular file", file); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { audit_msg(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf, sizeof(buf), &lineno, file)) { // convert line into name-value pair const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. audit_msg(LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, file); break; case 2: // no '=' sign audit_msg(LOG_ERR, "Missing equal sign for line %d in %s", lineno, file); break; default: // something else went wrong... audit_msg(LOG_ERR, "Unknown error for line %d in %s", lineno, file); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.values == NULL) { fclose(f); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { audit_msg(LOG_ERR, "Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, file); fclose(f); return 1; } /* Check number of options * nv.nvalues is always >= 1, because that's the right part of a 'key = value' conf line */ const int noptions = nv.nvalues - 1; if (kw->max_options != -1 && kw->max_options < noptions) { audit_msg(LOG_ERR, "Keyword \"%s\" has invalid options " "in line %d of %s", nv.name, lineno, file); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(&nv, lineno, config); if (rc != 0) { fclose(f); return 1; // local parser puts message out } nv_free(&nv); lineno++; } fclose(f); config->name = strdup(basename(file)); if (lineno > 1) return sanity_check(config, file); return 0; } static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file) { int too_long = 0; while (fgets_unlocked(buf, size, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) { if (!too_long) { *ptr = 0; return buf; } // Reset and start with the next line too_long = 0; *lineno = *lineno + 1; } else { // If a line is too long skip it. // Only output 1 warning if (!too_long) audit_msg(LOG_ERR, "Skipping line %d in %s: too long", *lineno, file); too_long = 1; } } return NULL; } static void nv_free(struct nv_pair *nv) { free(nv->values); } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr, *saved; nv->name = NULL; nv->values = NULL; nv->nvalues = 0; ptr = strtok_r(buf, " ", &saved); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = strtok_r(NULL, " ", &saved); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value part */ while ((ptr = strtok_r(NULL, " ", &saved)) != NULL) { nv->values = realloc(nv->values, (nv->nvalues + 1) * sizeof(char *)); if (nv->values == NULL) { return 1; } nv->values[nv->nvalues++] = ptr; } /* Check if at least 1 value was present */ if (nv->values == NULL) return 1; /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int active_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { int i; for (i=0; active[i].name != NULL; i++) { if (strcasecmp(nv->values[0], active[i].name) == 0) { config->active = active[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->values[0], line); return 1; } static int direction_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { int i; for (i=0; directions[i].name != NULL; i++) { if (strcasecmp(nv->values[0], directions[i].name) == 0) { config->direction = directions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->values[0], line); return 1; } static const char *BUILTIN_PATH="/sbin/audisp-af_unix"; static int path_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { char *dir = NULL, *tdir; if (nv->values == NULL) { config->path = NULL; return 0; } if (strncasecmp(nv->values[0], "builtin_", 8) == 0) { audit_msg(LOG_WARNING, "Option %s line %d is obsolete - using %s", nv->values[0], line, BUILTIN_PATH); config->path = strdup(BUILTIN_PATH); return 0; } /* get dir form name. */ tdir = strdup(nv->values[0]); if (tdir) dir = dirname(tdir); if (dir == NULL || strlen(dir) < 4) { // '/var' is shortest dirname audit_msg(LOG_ERR, "The directory name: %s is too short - line %d", dir, line); free(tdir); return 1; } free((void *)tdir); free((void *)config->path); config->path = strdup(nv->values[0]); if (config->path == NULL) return 1; return 0; } static int service_type_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { int i; for (i=0; service_type[i].name != NULL; i++) { if (strcasecmp(nv->values[0], service_type[i].name) == 0) { config->type = service_type[i].option; if (config->type == S_BUILTIN) { audit_msg(LOG_WARNING, "Option %s line %d is obsolete - update it", nv->values[0], line); config->type = S_ALWAYS; } return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->values[0], line); return 1; } static int args_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { config->args = calloc(nv->nvalues, sizeof(char *)); config->nargs = nv->nvalues; for (int i = 0; i < nv->nvalues; i++) { config->args[i] = strdup(nv->values[nv->nvalues - i - 1]); } return 0; } static int format_parser(struct nv_pair *nv, int line, plugin_conf_t *config) { int i; for (i=0; formats[i].name != NULL; i++) { if (strcasecmp(nv->values[0], formats[i].name) == 0) { config->format = formats[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->values[0], line); return 1; } /* * This function is where we do the integrated check of the audispd config * options. At this point, all fields have been read. Returns 0 if no * problems and 1 if problems detected. */ static int sanity_check(plugin_conf_t *config, const char *file) { /* Error checking */ if (config->active == A_YES) { struct stat buf; if (config->path == NULL) { audit_msg(LOG_ERR, "Error - plugin (%s) is active but no path given", file); return 1; } // Don't check builtins if (strncasecmp(config->path, "builtin_", 8) == 0) goto out; /* If the file exists, see that its regular, owned by root, * and not world anything */ if (stat(config->path, &buf) < 0) { audit_msg(LOG_ERR, "Unable to stat %s (%s)", config->path, strerror(errno)); return 1; } if (!S_ISREG(buf.st_mode)) { audit_msg(LOG_ERR, "%s is not a regular file", config->path); return 1; } if (buf.st_uid != 0) { audit_msg(LOG_ERR, "%s is not owned by root", config->path); return 1; } if ((buf.st_mode & (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP)) != (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP)) { audit_msg(LOG_ERR, "%s permissions should be at least 0550", config->path); return 1; } // Passes, record inode config->inode = buf.st_ino; } out: return 0; } void free_pconfig(plugin_conf_t *config) { int i; if (config == NULL) return; for (i = 0; i < config->nargs; i++) { free(config->args[i]); } free(config->args); if (config->plug_pipe[0] >= 0) close(config->plug_pipe[0]); if (config->plug_pipe[1] >= 0) close(config->plug_pipe[1]); free((void *)config->path); free((void *)config->name); } audit-userspace-4.0.5/audisp/audispd-pconfig.h000066400000000000000000000036471501761310600213420ustar00rootroot00000000000000/* audispd-pconfig.h -- * Copyright 2007,2013,2023 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUDISPD_PCONFIG_H #define AUDISPD_PCONFIG_H #include #include "libaudit.h" typedef enum { A_NO, A_YES } active_t; typedef enum { D_UNSET, D_IN, D_OUT } direction_t; typedef enum { S_ALWAYS, S_BUILTIN } service_t; typedef enum { F_BINARY, F_STRING } format_t; typedef struct plugin_conf { active_t active; /* Current state - active or not */ direction_t direction; /* in or out kind of plugin */ const char *path; /* path to binary */ service_t type; /* builtin or always */ char **args; /* args to be passed to plugin */ int nargs; format_t format; /* Event format */ int plug_pipe[2]; /* Communication pipe for events */ pid_t pid; /* Used to signal children */ ino_t inode; /* Use to see if new binary was installed */ int checked; /* Used for internal housekeeping on HUP */ char *name; /* Used to distinguish plugins for HUP */ unsigned restart_cnt; /* Number of times its crashed */ } plugin_conf_t; void clear_pconfig(plugin_conf_t *config); int load_pconfig(plugin_conf_t *config, char *file); void free_pconfig(plugin_conf_t *config); #endif audit-userspace-4.0.5/audisp/audispd.c000066400000000000000000000403751501761310600177110ustar00rootroot00000000000000/* audispd.c -- * Copyright 2007-08,2013,2016-23 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "audispd-pconfig.h" #include "audispd-config.h" #include "audispd-llist.h" #include "queue.h" #include "libaudit.h" #include "common.h" #include "private.h" /* Global Data */ #ifdef HAVE_ATOMIC static ATOMIC_INT stop = 0; ATOMIC_INT disp_hup = 0; #else static volatile ATOMIC_INT stop = 0; volatile ATOMIC_INT disp_hup = 0; #endif /* Local data */ static daemon_conf_t daemon_config; static conf_llist plugin_conf; static pthread_t outbound_thread; static int need_queue_depth_change = 0; /* Local function prototypes */ static void signal_plugins(int sig); static int event_loop(void); static int safe_exec(plugin_conf_t *conf); static void *outbound_thread_main(void *arg); static int write_to_plugin(event_t *e, const char *string, size_t string_len, lnode *conf) __attr_access ((__read_only__, 2, 3)); /* * Handle child plugins when they exit */ void plugin_child_handler(pid_t pid) { if (pid > 0) { // Mark the child pid as 0 in the configs lnode *tpconf; plist_first(&plugin_conf); tpconf = plist_get_cur(&plugin_conf); while (tpconf) { if (tpconf->p && tpconf->p->pid == pid) { tpconf->p->pid = 0; break; } tpconf = plist_next(&plugin_conf); } } } static int count_dots(const char *s) { const char *ptr; int cnt = 0; while ((ptr = strchr(s, '.'))) { cnt++; s = ptr + 1; } return cnt; } static void load_plugin_conf(conf_llist *plugin) { DIR *d; /* init plugin list */ plist_create(plugin); /* read configs */ d = opendir(daemon_config.plugin_dir); if (d) { struct dirent *e; while ((e = readdir(d))) { plugin_conf_t config; char fname[PATH_MAX]; const char *ext, *reason = NULL; if (e->d_type != DT_REG) reason = "not a regular file"; else if (e->d_name[0] == '.') reason = "hidden file"; else if (count_dots(e->d_name) > 1) reason = "backup file"; else if ((ext = strrchr(e->d_name, '.')) && strcmp(ext, ".conf") != 0) reason = "file without .conf suffix"; if (reason) { audit_msg(LOG_DEBUG, "Skipping %s plugin due to %s", e->d_name, reason); continue; } snprintf(fname, sizeof(fname), "%s/%s", daemon_config.plugin_dir, e->d_name); clear_pconfig(&config); if (load_pconfig(&config, fname) == 0) { /* Push onto config list only if active */ if (config.active == A_YES) plist_append(plugin, &config); else free_pconfig(&config); } else audit_msg(LOG_ERR, "Skipping %s plugin due to errors", e->d_name); } closedir(d); } } static int start_one_plugin(lnode *conf) { if (conf->p->restart_cnt > daemon_config.max_restarts) return 1; if (conf->p->type == S_ALWAYS) { if (safe_exec(conf->p)) { audit_msg(LOG_ERR, "Error running %s (%s) continuing without it", conf->p->path, strerror(errno)); conf->p->active = A_NO; return 0; } /* Close the parent's read side */ close(conf->p->plug_pipe[0]); conf->p->plug_pipe[0] = -1; /* Avoid leaking descriptor */ fcntl(conf->p->plug_pipe[1], F_SETFD, FD_CLOEXEC); } return 1; } static int start_plugins(conf_llist *plugin) { /* spawn children */ lnode *conf; int active = 0; plist_first(plugin); conf = plist_get_cur(plugin); if (conf == NULL || conf->p == NULL) return active; do { if (conf->p && conf->p->active == A_YES) { if (start_one_plugin(conf)) active++; } } while ((conf = plist_next(plugin))); return active; } static void copy_config(const struct daemon_conf *c) { if (c->q_depth > daemon_config.q_depth) need_queue_depth_change = 1; daemon_config.q_depth = c->q_depth; daemon_config.overflow_action = c->overflow_action; daemon_config.max_restarts = c->max_restarts; if (daemon_config.plugin_dir == NULL) daemon_config.plugin_dir = c->plugin_dir ? strdup(c->plugin_dir) : NULL; else if (daemon_config.plugin_dir && c->plugin_dir && strcmp(daemon_config.plugin_dir, c->plugin_dir)) { free(daemon_config.plugin_dir); daemon_config.plugin_dir = strdup(c->plugin_dir); } // else c->plugin_dir is NULL or they are the same // Either way, let's leave them alone. } static int reconfigure(void) { conf_llist tmp_plugin; lnode *tpconf; if (need_queue_depth_change) { need_queue_depth_change = 0; increase_queue_depth(daemon_config.q_depth); } reset_suspended(); /* The idea for handling SIGHUP to children goes like this: * 1) load the current config in temp list * 2) mark all in real list unchecked * 3) for each one in tmp list, scan old list * 4) if new, start it, append to list, mark done * 5) else check if there was a change to active state * 6) if so, copy config over and start * 7) If no change, send sighup to non-builtins and mark done * 8) Finally, scan real list for unchecked, terminate and deactivate */ load_plugin_conf(&tmp_plugin); plist_mark_all_unchecked(&plugin_conf); plist_first(&tmp_plugin); tpconf = plist_get_cur(&tmp_plugin); while (tpconf && tpconf->p) { lnode *opconf; opconf = plist_find_name(&plugin_conf, tpconf->p->name); if (opconf == NULL) { /* We have a new service */ if (tpconf->p->active == A_YES) { tpconf->p->checked = 1; plist_last(&plugin_conf); plist_append(&plugin_conf, tpconf->p); free(tpconf->p); tpconf->p = NULL; start_one_plugin(plist_get_cur(&plugin_conf)); } } else { if (opconf->p->active == tpconf->p->active) { /* If active and no state change, sighup it */ if (opconf->p->type == S_ALWAYS && opconf->p->active == A_YES) { if (opconf->p->inode==tpconf->p->inode){ if (opconf->p->pid) kill(opconf->p->pid, SIGHUP); } else { /* Binary changed, restart */ audit_msg(LOG_INFO, "Restarting %s since binary changed", opconf->p->path); if (opconf->p->pid) kill(opconf->p->pid, SIGTERM); usleep(50000); // 50 msecs close(opconf->p->plug_pipe[1]); opconf->p->plug_pipe[1] = -1; opconf->p->pid = 0; start_one_plugin(opconf); opconf->p->inode = tpconf->p->inode; } } opconf->p->checked = 1; } else { /* A change in state */ if (tpconf->p->active == A_YES) { /* starting - copy config and exec */ free_pconfig(opconf->p); free(opconf->p); opconf->p = tpconf->p; opconf->p->checked = 1; start_one_plugin(opconf); tpconf->p = NULL; } } } tpconf = plist_next(&tmp_plugin); } /* Now see what's left over */ while ( (tpconf = plist_find_unchecked(&plugin_conf)) ) { /* Anything not checked is something removed from the config */ tpconf->p->active = A_NO; audit_msg(LOG_INFO, "Terminating %s because its now inactive", tpconf->p->path); if (tpconf->p->type == S_ALWAYS) { if (tpconf->p->pid) kill(tpconf->p->pid, SIGTERM); close(tpconf->p->plug_pipe[1]); } tpconf->p->plug_pipe[1] = -1; tpconf->p->pid = 0; tpconf->p->checked = 1; } /* Release memory from temp config */ plist_first(&tmp_plugin); tpconf = plist_get_cur(&tmp_plugin); while (tpconf) { free_pconfig(tpconf->p); tpconf = plist_next(&tmp_plugin); } plist_clear(&tmp_plugin); return plist_count_active(&plugin_conf); } /* * Return 0 on success and 1 on failure * * Call tree: auditd.c main * auditd-dispatch.c init_dispatcher * * And: auditd-event.c reconfigure * auditd-dispatch.c reconfigure_dispatcher * * */ int libdisp_init(const struct daemon_conf *c) { int i; /* Init the dispatcher's config */ copy_config(c); /* Load all plugin configs */ load_plugin_conf(&plugin_conf); /* If no plugins - exit */ if (plist_count(&plugin_conf) == 0) { free(daemon_config.plugin_dir); daemon_config.plugin_dir = NULL; audit_msg(LOG_NOTICE, "No plugins found, not dispatching events"); return 0; } /* Plugins are started with the auditd priority */ i = start_plugins(&plugin_conf); /* Let the queue initialize */ init_queue(daemon_config.q_depth); audit_msg(LOG_INFO, "audit dispatcher initialized with q_depth=%d and %d active plugins", daemon_config.q_depth, i); /* Create outbound thread */ pthread_create(&outbound_thread, NULL, outbound_thread_main, NULL); pthread_detach(outbound_thread); return 0; } /* outbound thread - dequeue data to plugins */ static void *outbound_thread_main(void *arg) { lnode *conf; sigset_t sigs; /* This is a worker thread. Don't handle signals. */ sigemptyset(&sigs); sigaddset(&sigs, SIGTERM); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGUSR1); sigaddset(&sigs, SIGUSR2); sigaddset(&sigs, SIGCHLD); sigaddset(&sigs, SIGCONT); pthread_sigmask(SIG_SETMASK, &sigs, NULL); /* Start event loop */ while (event_loop()) { if (reconfigure() == 0) { audit_msg(LOG_INFO, "After reconfigure, there are no active plugins, exiting"); break; } AUDIT_ATOMIC_STORE(disp_hup, 0); } /* Tell plugins we are going down */ signal_plugins(SIGTERM); /* Release configs */ plist_first(&plugin_conf); conf = plist_get_cur(&plugin_conf); while (conf) { free_pconfig(conf->p); conf = plist_next(&plugin_conf); } plist_clear(&plugin_conf); /* Cleanup the queue */ destroy_queue(); free(daemon_config.plugin_dir); daemon_config.plugin_dir = NULL; audit_msg(LOG_DEBUG, "Finished cleaning up dispatcher"); return 0; } static int safe_exec(plugin_conf_t *conf) { char **argv; int pid, i; struct sigaction sa; /* Set up IPC with child */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, conf->plug_pipe) != 0) return -1; pid = fork(); if (pid > 0) { conf->pid = pid; return 0; /* Parent...normal exit */ } if (pid < 0) { close(conf->plug_pipe[0]); close(conf->plug_pipe[1]); conf->pid = 0; return -1; /* Failed to fork */ } /* Set up comm with child. It reads stdin so put the pipe there. */ if (dup2(conf->plug_pipe[0], 0) < 0) { close(conf->plug_pipe[0]); close(conf->plug_pipe[1]); conf->pid = 0; return -1; /* Failed to fork */ } #ifdef HAVE_CLOSE_RANGE close_range(3, ~0U, 0); /* close all past stderr */ #else for (i=3; i<24; i++) /* Arbitrary number */ close(i); #endif argv = calloc(conf->nargs + 2, sizeof(char *)); if (argv == NULL) { return -1; } /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); argv[0] = (char *)conf->path; for (i = 0; i < conf->nargs; i++) { argv[i+1] = conf->args[conf->nargs-i-1]; } argv[conf->nargs+1] = NULL; execve(conf->path, argv, NULL); exit(1); /* Failed to exec */ } static void signal_plugins(int sig) { lnode *conf; plist_first(&plugin_conf); conf = plist_get_cur(&plugin_conf); while (conf) { if (conf->p && conf->p->pid && conf->p->type == S_ALWAYS) kill(conf->p->pid, sig); conf = plist_next(&plugin_conf); } } static int write_to_plugin(event_t *e, const char *string, size_t string_len, lnode *conf) { int rc; if (conf->p->format == F_STRING) { do { rc = write(conf->p->plug_pipe[1], string, string_len); } while (rc < 0 && errno == EINTR); } else { struct iovec vec[2]; vec[0].iov_base = &e->hdr; vec[0].iov_len = sizeof(struct audit_dispatcher_header); vec[1].iov_base = e->data; vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH; do { rc = writev(conf->p->plug_pipe[1], vec, 2); } while (rc < 0 && errno == EINTR); } return rc; } /* Returns 0 on stop, and 1 on HUP */ static char fmt_buf[FORMAT_BUF_LEN]; static int event_loop(void) { /* Figure out the format for the af_unix socket */ while (AUDIT_ATOMIC_LOAD(stop) == 0) { event_t *e; char *ptr, unknown[32]; int len; lnode *conf; /* This is where we block until we have an event */ e = dequeue(); if (e == NULL) { if (AUDIT_ATOMIC_LOAD(disp_hup)) return 1; continue; } // Protocol 1 is not formatted if (e->hdr.ver == AUDISP_PROTOCOL_VER) { const char *type; /* Get the event formatted */ type = audit_msg_type_to_name(e->hdr.type); if (type == NULL) { snprintf(unknown, sizeof(unknown), "UNKNOWN[%u]", e->hdr.type); type = unknown; } len = snprintf(fmt_buf, sizeof(fmt_buf), "type=%s msg=%.*s\n", type, e->hdr.size, e->data); // Protocol 2 events are already formatted - just copy } else if (e->hdr.ver == AUDISP_PROTOCOL_VER2) { size_t to_copy = e->hdr.size; if (to_copy > sizeof(fmt_buf) - 2) to_copy = sizeof(fmt_buf) - 2; // was snprintf, this is faster memcpy(fmt_buf, e->data, to_copy); fmt_buf[to_copy] = '\n'; fmt_buf[to_copy + 1] = '\0'; len = (int)(to_copy + 1); } else len = 0; if (len <= 0) { free(e); /* Either corrupted event or no memory */ continue; } /* Strip newlines from event record except the last one */ ptr = fmt_buf; while ((ptr = strchr(ptr, 0x0A)) != NULL) { if (ptr != &fmt_buf[len-1]) *ptr = ' '; else break; /* Done - exit loop */ } /* Distribute event to the plugins */ plist_first(&plugin_conf); conf = plist_get_cur(&plugin_conf); do { if (conf == NULL || conf->p == NULL) continue; if (conf->p->active == A_NO || AUDIT_ATOMIC_LOAD(stop)) continue; /* Now send the event to the child */ if (conf->p->type == S_ALWAYS && !AUDIT_ATOMIC_LOAD(stop)) { int rc; rc = write_to_plugin(e, fmt_buf, len, conf); if (rc < 0 && errno == EPIPE) { /* Child disappeared ? */ if (!AUDIT_ATOMIC_LOAD(stop)) audit_msg(LOG_ERR, "plugin %s terminated unexpectedly", conf->p->path); conf->p->pid = 0; conf->p->restart_cnt++; close(conf->p->plug_pipe[1]); conf->p->plug_pipe[1] = -1; conf->p->active = A_NO; if (!AUDIT_ATOMIC_LOAD(stop) && conf->p->restart_cnt > daemon_config.max_restarts) { audit_msg(LOG_ERR, "plugin %s has exceeded max_restarts", conf->p->path); } if (!AUDIT_ATOMIC_LOAD(stop) && start_one_plugin(conf)) { rc = write_to_plugin(e, fmt_buf, len, conf); audit_msg(LOG_NOTICE, "plugin %s was restarted", conf->p->path); conf->p->active = A_YES; } } } } while (!AUDIT_ATOMIC_LOAD(stop) && (conf = plist_next(&plugin_conf))); /* Done with the memory...release it */ free(e); if (AUDIT_ATOMIC_LOAD(disp_hup)) break; } audit_msg(LOG_DEBUG, "Dispatcher event loop exit"); if (AUDIT_ATOMIC_LOAD(stop)) return 0; else return 1; } /* returns > 0 if plugins and 0 if none */ int libdisp_active(void) { // If there's no plugins, the other thread is dead return plist_count(&plugin_conf); } /* returns 0 on success and -1 on error */ int libdisp_enqueue(event_t *e) { return enqueue(e, &daemon_config); } void libdisp_nudge_queue(void) { // Only nudge if there is something to nudge if (plist_count(&plugin_conf)) nudge_queue(); } /* * Called by: auditd-event.c reconfigure * auditd-dispatch.c reconfigure_dispatcher */ void libdisp_reconfigure(const struct daemon_conf *c) { // If the dispatcher thread is dead, start a new one if (plist_count(&plugin_conf) == 0) libdisp_init(c); else { // Otherwise we do a reconfigure copy_config(c); AUDIT_ATOMIC_STORE(disp_hup, 1); nudge_queue(); } } void libdisp_write_queue_state(FILE *f) { fprintf(f, "Number of active plugins = %u\n", plist_count(&plugin_conf)); write_queue_state(f); } void libdisp_resume(void) { resume_queue(); } /* Used during startup and something failed */ void libdisp_shutdown(void) { AUDIT_ATOMIC_STORE(stop, 1); libdisp_nudge_queue(); } audit-userspace-4.0.5/audisp/libdisp.h000066400000000000000000000010771501761310600177070ustar00rootroot00000000000000#ifndef LIBDISP_HEADERS #define LIBDISP_HEADERS #include #include "libaudit.h" #include "auditd-config.h" typedef struct event { struct audit_dispatcher_header hdr; char data[MAX_AUDIT_MESSAGE_LENGTH]; } event_t; int libdisp_init(const struct daemon_conf *config); void libdisp_shutdown(void); void libdisp_reconfigure(const struct daemon_conf *config); void plugin_child_handler(pid_t pid); int libdisp_enqueue(event_t *e); int libdisp_active(void); void libdisp_nudge_queue(void); void libdisp_write_queue_state(FILE *f); void libdisp_resume(void); #endif audit-userspace-4.0.5/audisp/plugins/000077500000000000000000000000001501761310600175645ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/Makefile.am000066400000000000000000000020451501761310600216210ustar00rootroot00000000000000# Makefile.am -- # Copyright 2007-08,2018-23 Red Hat Inc. # All Rights Reserved. # # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig SUBDIRS = af_unix remote syslog filter if ENABLE_EXPERIMENTAL SUBDIRS += ids statsd endif if ENABLE_ZOS_REMOTE SUBDIRS += zos-remote endif audit-userspace-4.0.5/audisp/plugins/af_unix/000077500000000000000000000000001501761310600212155ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/af_unix/Makefile.am000066400000000000000000000035021501761310600232510ustar00rootroot00000000000000# Makefile.am-- # Copyright 2023 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig CONF_FILES = af_unix.conf EXTRA_DIST = $(CONF_FILES) $(man_MANS) # FIXME add common temporarily AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/audisp -I${top_srcdir}/common LIBS = ${top_builddir}/lib/libaudit.la prog_confdir = $(sysconfdir)/audit plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = af_unix.conf sbin_PROGRAMS = audisp-af_unix man_MANS = audisp-af_unix.8 audisp_af_unix_DEPENDENCIES = ${top_builddir}/lib/libaudit.la audisp_af_unix_SOURCES = audisp-af_unix.c audisp_af_unix_CFLAGS = -fPIE -DPIE -g -D_GNU_SOURCE -Wundef ${WFLAGS} audisp_af_unix_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now audisp_af_unix_LDADD = $(CAPNG_LDADD) ${top_builddir}/lib/libaudit.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} for i in $(CONF_FILES); do \ $(INSTALL_DATA) -D -m 640 ${srcdir}/"$$i" \ ${DESTDIR}${plugin_confdir}; \ done uninstall-hook: for i in $(CONF_FILES); do \ rm ${DESTDIR}${plugin_confdir}/"$$i"; \ done audit-userspace-4.0.5/audisp/plugins/af_unix/af_unix.conf000066400000000000000000000005561501761310600235230ustar00rootroot00000000000000# This file controls the configuration of the # af_unix socket plugin. It simply takes events # and writes them to a unix domain socket. This # plugin can take 2 arguments, the path for the # socket and the socket permissions in octal. active = no direction = out path = /sbin/audisp-af_unix type = always args = 0640 /var/run/audispd_events string format = binary audit-userspace-4.0.5/audisp/plugins/af_unix/audisp-af_unix.8000066400000000000000000000031441501761310600242240ustar00rootroot00000000000000.TH AUDISP-AF_UNIX "8" "Apr 2023" "Red Hat" "System Administration Utilities" .SH NAME audisp-af_unix \- plugin to push audit events to an af_unix socket .SH SYNOPSIS .B audisp-af_unix [ \fIOPTIONS\fP ] .SH DESCRIPTION \fBaudisp-af_unix\fP is a plugin for the audit event dispatcher that sends audit events to an af_unix socket where other applications can read events. The .B args line of the .B af_unix.conf file expects three arguments: access mode, socket path, and output format. The access mode determines the permissions for the socket and defaults to 0640. The socket path specifies where the socket will be created, with the default location being /var/run/audispd_events. The output format determines the format in which events are delivered to the socket and supports two options: "string" and "binary". The "string" format delivers events in a human-readable form, while the "binary" format delivers events in their binary representation, which is essential for applications that need to process events in binary and reconstruct headers accurately. If the output format is not specified, the plugin defaults to the "string" format. The .B af_unix.conf file must also include the line \fBformat = binary\fP. This setting specifies the input format that the \fBaudisp-af_unix\fP plugin expects from the audit event dispatcher. It ensures that the input delivered to the plugin is in binary format, enabling the plugin to reconstruct headers in their proper binary structure. .SH FILES /etc/audit/plugins/af_unix.conf /etc/audit/auditd.conf .SH "SEE ALSO" .BR auditd.conf (8), .BR auditd-plugins (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/audisp/plugins/af_unix/audisp-af_unix.c000066400000000000000000000234211501761310600242770ustar00rootroot00000000000000/* * af_unix.c - implementation of the audisp-af_unix plugin * Copyright (c) 2023 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCAP_NG #include #endif #include "libaudit.h" #include "common.h" // FIXME temporary #include "audispd-pconfig.h" #define DEFAULT_PATH "/var/run/audispd_events" #define MAX_AUDIT_EVENT_FRAME_SIZE (sizeof(struct audit_dispatcher_header) + MAX_AUDIT_MESSAGE_LENGTH) //#define DEBUG /* Global Data */ static volatile int stop = 0, hup = 0; char rx_buf[MAX_AUDIT_EVENT_FRAME_SIZE+1]; int sock = -1, conn = -1, client = 0; struct pollfd pfd[3]; unsigned mode = 0; format_t format = -1; char *path = NULL; int inbound_protocol = -1; /* * SIGTERM handler */ static void term_handler(int sig) { stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler(int sig) { hup = 1; } int create_af_unix_socket(const char *spath, int mode) { struct sockaddr_un addr; socklen_t len; int rc, cmd, one = 1; sock = socket(PF_UNIX, SOCK_STREAM, 0); if (sock < 0) { syslog(LOG_ERR, "Couldn't open af_unix socket (%s)", strerror(errno)); return -1; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int)); #ifdef DEBUG printf("%o %s\n", mode, spath); #else memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; snprintf(&addr.sun_path[0], 108, "%.107s", spath); len = sizeof(addr); rc = bind(sock, (const struct sockaddr *)&addr, len); if (rc < 0) { syslog(LOG_ERR, "Couldn't bind af_unix socket (%s)", strerror(errno)); close(sock); return -1; } rc = chmod(spath, mode); if (rc < 0) { syslog(LOG_ERR, "Couldn't chmod %s to %04o (%s)", spath, mode, strerror(errno)); close(sock); unlink(spath); return -1; } // Put socket in nonblock mode and don't leak the descriptor cmd = fcntl(sock, F_GETFL); fcntl(sock, F_SETFL, cmd|FNDELAY|FD_CLOEXEC); // Make socket listening...won't block (void)listen(sock, 1); #endif return 0; } int setup_socket(int argc, char *argv[]) { for (int i = 1; i < argc; i++) { char *arg = argv[i]; if (isdigit((unsigned char)arg[0])) { // parse mode errno = 0; mode = strtoul(arg, NULL, 8); if (errno) { syslog(LOG_ERR, "Error converting %s (%s)", argv[i], strerror(errno)); mode = 0; } } else if (strchr(arg, '/') != NULL) { // parse path char* base; path = arg; // Make sure there are directories base = strchr(path, '/'); if (base) { DIR* d; char* dir = strdup(path); base = dirname(dir); d = opendir(base); if (d) { closedir(d); free(dir); } else { syslog(LOG_ERR, "Couldn't open %s (%s)", base, strerror(errno)); free(dir); exit(1); } } else { syslog(LOG_ERR, "Malformed path %s", path); exit(1); } } else { if (strcmp(arg, "string") == 0) format = F_STRING; else if (strcmp(arg, "binary") == 0) format = F_BINARY; else syslog(LOG_ERR, "Invalid format detected"); } } if (mode == 0 || path == NULL || format == -1) { syslog(LOG_ERR, "Bad or not enough arguments, using defaults"); if (mode == 0) { mode = 0640; syslog(LOG_INFO, "Using default mode"); } if (path == NULL) { path = DEFAULT_PATH; syslog(LOG_INFO, "Using default path"); } if (format == -1) { format = F_STRING; syslog(LOG_INFO, "Using default format"); } } return create_af_unix_socket(path, mode); } static int event_to_string(struct audit_dispatcher_header *hdr, char *data, char **out, int *outlen) { char *v = NULL, *ptr, unknown[32]; int len; if (inbound_protocol == F_BINARY) { if (hdr->ver == AUDISP_PROTOCOL_VER) { const char *type; /* Get the event formatted */ type = audit_msg_type_to_name(hdr->type); if (type == NULL) { snprintf(unknown, sizeof(unknown), "UNKNOWN[%u]", hdr->type); type = unknown; } len = asprintf(&v, "type=%s msg=%.*s", type, hdr->size, data); } else if (inbound_protocol == F_BINARY && hdr->ver == AUDISP_PROTOCOL_VER2) { // Protocol 2 events are already formatted len = asprintf(&v, "%.*s", hdr->size, data); } else len = 0; } else if (inbound_protocol == F_STRING) { // Inbound strings start at the hdr len = asprintf(&v, "%s", (char *)hdr); } else len = 0; if (len <= 0) { *out = NULL; *outlen = 0; return -1; } /* Strip newlines from event record */ ptr = v; while ((ptr = strchr(ptr, 0x0A)) != NULL) { if (ptr != &v[len-1]) *ptr = ' '; else break; /* Done - exit loop */ } *out = v; *outlen = len; return 1; } void read_audit_record(int ifd) { do { int len; // Read stdin if ((len = audit_fgets(rx_buf, MAX_AUDIT_EVENT_FRAME_SIZE + 1, ifd)) > 0) { #ifdef DEBUG write(1, rx_buf, len); #endif if (client) { // Send it to the client int rc; struct audit_dispatcher_header *hdr = (struct audit_dispatcher_header *)rx_buf; char *data = rx_buf + sizeof(struct audit_dispatcher_header); if (inbound_protocol == -1) { if (hdr->ver == AUDISP_PROTOCOL_VER || hdr->ver == AUDISP_PROTOCOL_VER2) inbound_protocol = F_BINARY; else inbound_protocol = F_STRING; } if (format == F_STRING) { char *str = NULL; int str_len = 0; if (event_to_string(hdr, data, &str, &str_len) < 0) { // what to do with error? continue; } do { rc = write(conn, str, str_len); } while (rc < 0 && errno == EINTR); free(str); } else if (format == F_BINARY) { struct iovec vec[2]; vec[0].iov_base = hdr; vec[0].iov_len = sizeof(struct audit_dispatcher_header); vec[1].iov_base = data; vec[1].iov_len = MAX_AUDIT_MESSAGE_LENGTH; do { rc = writev(conn, vec, 2); } while (rc < 0 && errno == EINTR); if (rc < 0 && errno == EPIPE) { close(conn); conn = -1; client = 0; audit_fgets_clear(); } //if (rc >= 0 && rc != len) { // what to do with leftovers? //} } } } else if (audit_fgets_eof()) stop = 1; } while (audit_fgets_more(MAX_AUDIT_EVENT_FRAME_SIZE)); } void accept_connection(void) { int tmp_conn; do { tmp_conn = accept4(sock, NULL,NULL, SOCK_NONBLOCK|SOCK_CLOEXEC); } while (tmp_conn < 0 && errno == EINTR); if (tmp_conn >= 0) { if (conn < 0) { syslog(LOG_INFO, "Client connected"); client = 1; conn = tmp_conn; } else close(tmp_conn); } } void event_loop(int ifd) { // setup poll pfd[0].fd = ifd; //stdin pfd[0].events = POLLIN; pfd[1].fd = sock; // listen socket pfd[1].events = POLLIN|POLLOUT; // loop on poll until stop - not doing HUP for now while (!stop) { int rc; if (client) { pfd[2].fd = conn; // the client pfd[2].events = POLLHUP; } rc = poll(pfd, 2 + client, -1); if (rc < 0) { if (errno == EINTR) continue; syslog(LOG_WARNING, "Poll error (%s), exiting", strerror(errno)); return; } if (rc > 0) { if (client && (pfd[2].revents & POLLHUP)) { // client hung up, do this first in case // an inbound audit record is available close(conn); conn = -1; client = 0; audit_fgets_clear(); } if (pfd[0].revents & POLLIN) { // Inbound audit event read_audit_record(ifd); } // auditd closed it's socket, exit if (pfd[0].revents & POLLHUP) { syslog(LOG_INFO,"Auditd closed it's socket - exiting"); return; } if (pfd[1].revents & (POLLIN|POLLOUT)) { // someone connected, accept it accept_connection(); } } } if (stop == 1) syslog(LOG_INFO, "audisp-af_unix plugin is exiting on TERM request"); } int main(int argc, char *argv[]) { struct sigaction sa; int i, ifd; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Ignore all signals by default */ sa.sa_handler = SIG_IGN; for (i=1; i= 0) close(conn); if (sock >= 0) close(sock); unlink(path); return 0; } audit-userspace-4.0.5/audisp/plugins/filter/000077500000000000000000000000001501761310600210515ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/filter/Makefile.am000066400000000000000000000036601501761310600231120ustar00rootroot00000000000000# Makefile.am -- # Copyright 2024 Red Hat Inc. # All Rights Reserved. # # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Attila Lakatos # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = filter.conf audisp-filter.conf $(man_MANS) AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/common -I${top_srcdir}/auparse prog_confdir = $(sysconfdir)/audit prog_conf = audisp-filter.conf plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = filter.conf sbin_PROGRAMS = audisp-filter man_MANS = audisp-filter.8 audisp_filter_DEPENDENCIES = ${top_builddir}/common/libaucommon.la ${top_builddir}/auparse/libauparse.la audisp_filter_SOURCES = audisp-filter.c audisp_filter_CFLAGS = -fPIE -DPIE -g -D_GNU_SOURCE -Wundef ${WFLAGS} audisp_filter_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now audisp_filter_LDADD = $(CAPNG_LDADD) ${top_builddir}/common/libaucommon.la ${top_builddir}/auparse/libauparse.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(prog_conf) ${DESTDIR}${prog_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) rm ${DESTDIR}${prog_confdir}/$(prog_conf) audit-userspace-4.0.5/audisp/plugins/filter/audisp-filter.8000066400000000000000000000062401501761310600237140ustar00rootroot00000000000000.TH AUDISP-SYSLOG "8" "February 2024" "Red Hat" "System Administration Utilities" .SH NAME audisp-filter \- plugin to filter audit events and forward them to other plugins .SH SYNOPSIS .B audisp-filter \fIMODE CONFIG_FILE BINARY\fP [ \fIBINARY_ARGS\fP ] .SH DESCRIPTION \fBaudisp-filter\fP is an audit event dispatcher plugin designed to filter out specific events based on its provided configuration. Moreover, it possesses the capability to forward the remaining logs to other plugins. The plugin is universally compatible, allowing seamless integration with any existing audit plugin that expects audit messages on its standard input. Currently it supports the following arguments: .RS .TP .B MODE The operational mode can be either allowlist or blocklist. In allowlist mode, the plugin forwards everything except for events that match the specified ausearch expressions in the configuration. Conversely, in blocklist mode, it refrains from forwarding anything except for events listed in the configuration. .TP .B CONFIG_FILE Path to the main configuration file containing ausearch expressions. .TP .B BINARY Path to an external program that will consistently receive filtered audit events through its standard input. .TP .B BINARY_ARGS Optionally, you can pass additional arguments to the external program. .RE .SH CONFIGURATION AND RULES EVALUATION Every single plugin that wants to benefit from the event filtering capability needs to create its own configuration file. It's a good practice to place this file inside the audit config directory, following the naming convention audisp-filter-pluginname.conf, for instance, .B audisp-filter-syslog.conf to filter audit events before sending them to syslog. Each line within a configuration represents an ausearch-expression (5). Internally, these expressions are joined using the OR operator. Therefore, every expression is substituted with (PE || CE), where PE represents the previous expression and CE denotes the current expression being processed. Lines starting with a .B '#' character are treated as comments and do not influence the final rule set. Upon the creation of an audit event, the filtering engine goes through the list of expressions, constructing the final expression representing our rule set. The event in question will be searched using this expression. The decision to forward an audit event to the configured binary depends on two factors: the operational mode of audisp-filter and whether the expression matches the ongoing event. .SH EXAMPLE Example1: Do not syslog audit events containing unsuccessful openat syscalls. First, in the plugin config, make sure that operation mode is set to allowlist, the binary points to /sbin/audispFyslog and provide any additional arguments if needed. Next, create the plugin specific config file with the content below. Before enabling the audit plugin, always make sure the syntax is correct. This can be checked by calling audisp-filter --check path/to/config/file. .B (type r= SYSCALL && syscall i= openat && success r= yes) .SH FILES /etc/audit/plugins/filter.conf /etc/audit/auditd.conf .SH "SEE ALSO" .BR auditd.conf (8), .BR ausearch-expression (5), .BR auditd-plugins (5). .SH AUTHOR Attila Lakatos audit-userspace-4.0.5/audisp/plugins/filter/audisp-filter.c000066400000000000000000000300211501761310600237610ustar00rootroot00000000000000/* audisp-filter.c -- * Copyright 2024 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Attila Lakatos * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCAP_NG #include #endif #include "auparse.h" #include "common.h" #include "libaudit.h" struct filter_rule { char* expr; int lineno; struct filter_rule* next; }; struct filter_list { struct filter_rule* head; struct filter_rule* tail; }; enum { ALLOWLIST, BLOCKLIST }; struct filter_conf { int mode; /* allowlist or blocklist */ const char* binary; /* external program that will receive filter audit events */ char** binary_args; /* arguments for external program */ const char* config_file; /* file containing audit expressions */ int only_check; /* just verify the syntax of the config_file and exit */ }; /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static int pipefd[2]; static int errors = 0; static struct filter_list list; pid_t cpid = -1; static struct filter_conf config = { .mode = -1, .binary = NULL, .binary_args = NULL, .config_file = NULL, .only_check = 0 }; static void handle_event(auparse_state_t* au, auparse_cb_event_t cb_event_type, void* user_data) { if (cb_event_type != AUPARSE_CB_EVENT_READY) return; int rc, forward_event; // Determine whether to forward or drop the event rc = ausearch_cur_event(au); if (rc > 0) { /* matched */ forward_event = (config.mode == ALLOWLIST) ? 0 : 1; } else if (rc == 0) { /* not matched */ forward_event = (config.mode == ALLOWLIST) ? 1 : 0; } else { syslog(LOG_ERR, "The ausearch_next_event returned %d", rc); return; } if (forward_event) { const int records = auparse_get_num_records(au); for (int i = 0; i < records; i++) { auparse_goto_record_num(au, i); const char* txt = auparse_get_record_text(au); // Need to add new line character to signal end of the current record if (write(pipefd[1], txt, strlen(txt)) == -1 || write(pipefd[1], "\n", 1) == -1) { syslog(LOG_ERR, "Failed to write to pipe"); return; } } } } static void free_args() { if (config.binary_args) { for (int i = 0; config.binary_args[i] != NULL; i++) { free(config.binary_args[i]); } free(config.binary_args); } } static int parse_args(int argc, const char* argv[]) { if (argc == 3 && (strcmp("--check", argv[1]) == 0)) { config.config_file = argv[2]; config.only_check = 1; return 0; } if (argc <= 3) { syslog(LOG_ERR, "Not enough command line arguments"); return 1; } if (strcasecmp(argv[1], "allowlist") == 0) config.mode = ALLOWLIST; else if (strcasecmp(argv[1], "blocklist") == 0) config.mode = BLOCKLIST; else { syslog(LOG_ERR, "Invalid mode '%s' specified, possible values are: allowlist, " "blocklist.", argv[1]); return 1; } config.config_file = argv[2]; config.binary = argv[3]; argc -= 3; argv += 3; config.binary_args = malloc(sizeof(char*) * (argc + 1)); /* +1 is for the last NULL */ if (!config.binary_args) return 1; for (int i = 0; i < argc; i++) { config.binary_args[i] = strdup(argv[i]); if (!config.binary_args[i]) { while (i > 0) { free(config.binary_args[--i]); } free(config.binary_args); return 1; } } config.binary_args[argc] = NULL; return 0; } static char* get_line(FILE* f, char* buf, unsigned size, int* lineno, const char* file) { int too_long = 0; while (fgets_unlocked(buf, size, f)) { /* remove newline */ char* ptr = strchr(buf, 0x0a); if (ptr) { if (!too_long) { *ptr = 0; return buf; } // Reset and start with the next line too_long = 0; *lineno = *lineno + 1; } else { // If a line is too long skip it. // Only output 1 warning if (!too_long) syslog(LOG_WARNING, "Skipping line %d in %s: too long", *lineno, file); too_long = 1; } } return NULL; } // static void print_rules(struct filter_list* list) { // struct filter_rule* rule; // int count = 0; // // for (rule = list->head; rule != NULL; rule = rule->next, count++) { // printf("Rule %d on line %d: %s\n", count, rule->lineno, rule->expr); // } // } static void reset_rules(struct filter_list* list) { list->head = list->tail = NULL; } static void free_rule(struct filter_rule* rule) { free(rule->expr); } static void free_rules(struct filter_list* list) { struct filter_rule* current = list->head, * to_delete; while (current != NULL) { to_delete = current; current = current->next; free_rule(to_delete); free(to_delete); } } static void append_rule(struct filter_list* list, struct filter_rule* rule) { if (list->head == NULL) { list->head = list->tail = rule; } else { list->tail->next = rule; list->tail = rule; } } static struct filter_rule* parse_line(char* line, int lineno) { struct filter_rule* rule; auparse_state_t* au; const char* buf[] = { NULL }; char* error = NULL; /* dummy instance of the audit parsing library, we use it to validate search expressions that will be added to the filter engine */ if ((au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf)) == NULL) { syslog(LOG_ERR, "The auparse_init failed"); return NULL; } // Skip whitespace while (*line == ' ') line++; // Empty line or it's a comment if (!*line || *line == '#') { auparse_destroy(au); return NULL; } if ((rule = malloc(sizeof(struct filter_rule))) == NULL) { auparse_destroy(au); return NULL; } rule->lineno = lineno; rule->next = NULL; if ((rule->expr = strdup(line)) == NULL) { auparse_destroy(au); free(rule); return NULL; } if (ausearch_add_expression(au, rule->expr, &error, AUSEARCH_RULE_OR) != 0) { syslog(LOG_ERR, "Invalid expression: %s (%s)", rule->expr, error); free_rule(rule); free(rule); rule = NULL; errors++; } auparse_destroy(au); return rule; } /* * Load rules from config into our linked list */ static int load_rules(struct filter_list* list) { int fd, lineno = 0; struct stat st; char buf[1024]; FILE* f; reset_rules(list); errors = 0; /* open the file */ if ((fd = open(config.config_file, O_RDONLY)) < 0) { if (errno != ENOENT) { syslog(LOG_ERR, "Error opening config file (%s)", strerror(errno)); return 1; } syslog(LOG_ERR, "Config file %s doesn't exist, skipping", config.config_file); return 1; } if (fstat(fd, &st) < 0) { syslog(LOG_ERR, "Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { syslog(LOG_ERR, "Error - %s isn't owned by root", config.config_file); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { syslog(LOG_ERR, "Error - %s is world writable", config.config_file); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { syslog(LOG_ERR, "Error - %s is not a regular file", config.config_file); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { syslog(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf, sizeof(buf), &lineno, config.config_file)) { lineno++; struct filter_rule* rule; if ((rule = parse_line(buf, lineno)) == NULL) continue; append_rule(list, rule); } fclose(f); return errors; } /* * SIGCHLD handler: reap exiting processes */ static void child_handler(int sig) { while (waitpid(-1, NULL, WNOHANG) > 0) ; /* empty */ stop = 1; } /* * SIGTERM handler */ static void term_handler(int sig) { kill(cpid, sig); stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler(int sig) { kill(cpid, sig); hup = 1; } static void reload_config(void) { hup = 0; struct filter_list new_list; /* load new rules */ if (load_rules(&new_list)) { syslog(LOG_INFO, "The rules were not reloaded because of a syntax error"); free_rules(&new_list); return; } /* remove unused previous rules */ free_rules(&list); list = new_list; syslog(LOG_INFO, "Successfully reloaded rules"); } int main(int argc, const char* argv[]) { auparse_state_t* au = NULL; struct sigaction sa; char buffer[MAX_AUDIT_MESSAGE_LENGTH]; /* validate args */ if (parse_args(argc, argv)) return 1; /* create a list of rules from config file */ if (load_rules(&list)) { free_rules(&list); free_args(); return 1; } /* validate the ruleset and exit */ if (config.only_check) { free_rules(&list); free_args(); return 0; } /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = child_handler; sigaction(SIGCHLD, &sa, NULL); #ifdef HAVE_LIBCAP_NG // Drop capabilities capng_clear(CAPNG_SELECT_BOTH); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "audisp-filter: unable to drop capabilities, continuing with " "elevated privileges"); #endif if (pipe(pipefd) == -1) { syslog(LOG_ERR, "audisp-filter: unable to open a pipe (%s)", strerror(errno)); return -1; } cpid = fork(); if (cpid == -1) { syslog(LOG_ERR, "audisp-filter: unable to create fork (%s)", strerror(errno)); return -1; } if (cpid == 0) { /* Child reads filtered input*/ close(pipefd[1]); dup2(pipefd[0], STDIN_FILENO); close(pipefd[0]); execve(config.binary, config.binary_args, NULL); syslog(LOG_ERR, "audisp-filter: execve failed (%s)", strerror(errno)); exit(1); } else { /* Parent reads input and forwards data after filters have been applied */ close(pipefd[0]); au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { syslog(LOG_ERR, "audisp-filter: failed to initialize auparse data feed"); kill(cpid, SIGTERM); return -1; } auparse_set_eoe_timeout(2); auparse_add_callback(au, handle_event, NULL, NULL); ausearch_set_stop(au, AUSEARCH_STOP_EVENT); // add rules(expressions) to the ausearch engine for (struct filter_rule* rule = list.head; rule != NULL; rule = rule->next) { char* error = NULL; int rc = ausearch_add_expression(au, rule->expr, &error, AUSEARCH_RULE_OR); if (rc != 0) { /* this should not happen because rules were pre-tested in parse_line() */ syslog(LOG_ERR, "Failed to add expression '%s' to ausearch (%s)", rule->expr, error); } free(error); } do { fd_set read_mask; int retval; int read_size = 1; /* Set to 1 so it's not EOF */ /* Load configuration */ if (hup) { reload_config(); } do { FD_ZERO(&read_mask); FD_SET(0, &read_mask); if (auparse_feed_has_data(au)) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; retval = select(1, &read_mask, NULL, NULL, &tv); } else retval = select(1, &read_mask, NULL, NULL, NULL); /* If we timed out & have events, shake them loose */ if (retval == 0 && auparse_feed_has_data(au)) auparse_feed_age_events(au); } while (retval == -1 && errno == EINTR && !hup && !stop); /* Now the event loop */ if (!stop && !hup && retval > 0) { while ((read_size = read(0, buffer, MAX_AUDIT_MESSAGE_LENGTH)) > 0) { auparse_feed(au, buffer, read_size); } } if (read_size == 0) /* EOF */ break; } while (stop == 0); auparse_flush_feed(au); ausearch_clear(au); auparse_destroy(au); } free_rules(&list); free_args(); return 0; } audit-userspace-4.0.5/audisp/plugins/filter/audisp-filter.conf000066400000000000000000000004561501761310600244750ustar00rootroot00000000000000# Here you can specify a list of ausearch-expression(8) # # In allowlist mode, the plugin forwards everything except # for events that match the specified ausearch expressions. # In blocklist mode, it refrains from forwarding anything # except for events matching these expressions. # See audisp-filteraudit-userspace-4.0.5/audisp/plugins/filter/filter.conf000066400000000000000000000011571501761310600232110ustar00rootroot00000000000000# # The audisp-filter plugin is designed to address # the need for event filtering in the Linux audit system. # It empowers users to selectively process audit events # based on specified criteria before they are e.g. forwarded # to syslog or sent to a remote destination for analysis. # The filter is generic and is designed to work in tandem # with other plugins which expect audit messages on their # standard input. # See audisp-filter(8) active = no direction = out path = /sbin/audisp-filter type = always args = allowlist /etc/audit/audisp-filter.conf /sbin/audisp-syslog LOG_USER LOG_INFO interpret format = string audit-userspace-4.0.5/audisp/plugins/ids/000077500000000000000000000000001501761310600203435ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/ids/Makefile.am000066400000000000000000000041371501761310600224040ustar00rootroot00000000000000# Makefile.am -- # Copyright 2021 Steve Grubb # All Rights Reserved. # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = audisp-ids.conf ids.conf TODO README.md SUBDIRS = rules AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse -I${top_srcdir}/common prog_confdir = $(sysconfdir)/audit prog_conf = ids.conf plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = audisp-ids.conf sbin_PROGRAMS = audisp-ids noinst_HEADERS = account.h avl.h ids_config.h gcc-attributes.h ids.h \ model_bad_event.h model_behavior.h nvpair.h origin.h \ reactions.h session.h timer-services.h audisp_ids_DEPENDENCIES = ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la ${top_builddir}/common/libaucommon.la audisp_ids_SOURCES = account.c avl.c ids.c ids_config.c model_bad_event.c \ model_behavior.c nvpair.c origin.c reactions.c session.c \ timer-services.c audisp_ids_CFLAGS = -D_GNU_SOURCE ${WFLAGS} audisp_ids_LDADD = ${top_builddir}/lib/libaudit.la \ ${top_builddir}/auparse/libauparse.la ${top_builddir}/common/libaucommon.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(prog_conf) ${DESTDIR}${prog_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) audit-userspace-4.0.5/audisp/plugins/ids/README.md000066400000000000000000000010041501761310600216150ustar00rootroot00000000000000This is an experimental Intrusion Detection System (IDS) plugin. It's goal is to either identify or react to suspicious activity. This is a work in progress and is subject to either be completed or dropped in it's entirety at its author's descretion. So, if you would like to test it and report issues or even contribute code feel free to do so. But please discuss the contribution first to ensure that its acceptable. This project uses the Linux Kernel Style Guideline. Please follow it if you wish to contribute. audit-userspace-4.0.5/audisp/plugins/ids/TODO000066400000000000000000000005261501761310600210360ustar00rootroot000000000000001) Add response audit events 2) Start getting whitelisting in place 3) verify timer services working correctly Test on live server 4) Support nftables 5) Support IPv6 6) Patch auditctl for new ids rules 7) Should we save state on shutdown and restore on start up? 8) Develop ids rules for more coverage of ATT&CK 9) More sophisticated models audit-userspace-4.0.5/audisp/plugins/ids/account.c000066400000000000000000000063271501761310600221530ustar00rootroot00000000000000/* account.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include "ids.h" #include "account.h" #include "reactions.h" // This holds info about all sessions struct account_avl{ avl_tree_t index; unsigned int count; }; static struct account_avl accounts; static account_data_t *cur = NULL; static int cmp_accounts(void *a, void *b) { return strcmp(((account_data_t *)a)->name, ((account_data_t *)b)->name); } void init_accounts(void) { accounts.count = 0; cur = NULL; avl_init(&accounts.index, cmp_accounts); } unsigned int get_num_accounts(void) { return accounts.count; } static int dump_account(void *entry, void *data) { FILE *f = data; account_data_t *a = entry; fprintf(f, "\n"); fprintf(f, " name: %s\n", a->name); fprintf(f, " karma: %u\n", a->karma); return 0; } void traverse_accounts(FILE *f) { fprintf(f, "Accounts\n"); fprintf(f, "========\n"); fprintf(f, "count: %u\n", accounts.count); avl_traverse(&accounts.index, dump_account, f); } static void free_account(account_data_t *a) { if (debug) my_printf("Account freeing %p", a); free((void *)a->name); free(a); } static void destroy_account(void) { avl_t *cur = accounts.index.root; account_data_t *a = (account_data_t *)avl_remove(&accounts.index, cur); if ((avl_t *)a != cur) my_printf("account: removal of invalid node"); // Now free any data pointed to by cur free_account(a); cur = NULL; } void new_account(const char *name) { account_data_t *tmp = (account_data_t *)malloc(sizeof(account_data_t)); if (tmp) { tmp->name = name ? strdup(name) : strdup(""); tmp->karma = 0; add_account(tmp); } } void destroy_accounts(void) { while (accounts.index.root) { accounts.count--; destroy_account(); } } int add_account(account_data_t *a) { account_data_t *tmp; if (debug) my_printf("Adding account %s", a->name); cur = NULL; tmp = (account_data_t *)avl_insert(&accounts.index, (avl_t *)(a)); if (tmp) { if (tmp != a) { if (debug) my_printf("account: duplicate name found"); free_account(a); return 1; } accounts.count++; cur = tmp; } else if (debug) my_printf("account: failed inserting name %s", a->name); return 0; } account_data_t *find_account(const char *name) { account_data_t tmp; if (name == NULL) return NULL; tmp.name = name; cur = (account_data_t *)avl_search(&accounts.index, (avl_t *) &tmp); return cur; } account_data_t *current_account(void) { return cur; } int del_account(const char *name) { account_data_t tmp1, *tmp2; tmp1.name = name; if (debug) my_printf("Deleting %s", name); cur = NULL; tmp2 = (account_data_t *)avl_remove(&accounts.index, (avl_t *) &tmp1); if (tmp2) { accounts.count--; if (strcmp(tmp2->name, name) != 0) { if (debug) my_printf("account: deleting unknown name"); return 1; } } else { if (debug) my_printf("account: didn't find name"); return 1; } // Now free any data pointed to by tmp2 free_account(tmp2); return 0; } void add_to_score_account(account_data_t *a, unsigned int adj) { cur = a; if (a == NULL) { if (debug) my_printf("Account NULL adding score"); return; } a->karma += adj; // Now invoke any reaction if (a->karma >= 5) { } } audit-userspace-4.0.5/audisp/plugins/ids/account.h000066400000000000000000000012501501761310600221460ustar00rootroot00000000000000/* account.h -- * * Authors: * Steve Grubb * */ #ifndef ACCOUNT_HEADER #define ACCOUNT_HEADER #include #include "avl.h" typedef struct account_data { avl_t avl; // This has to be first const char *name; unsigned int karma; } account_data_t; void init_accounts(void); void destroy_accounts(void); void new_account(const char *name); unsigned int get_num_accounts(void); void traverse_accounts(FILE *f); int add_account(account_data_t *a); account_data_t *find_account(const char *name); account_data_t *current_account(void); int del_account(const char *name); void add_to_score_account(account_data_t *a, unsigned int adj); #endif audit-userspace-4.0.5/audisp/plugins/ids/audisp-ids.conf000066400000000000000000000002441501761310600232540ustar00rootroot00000000000000# This file controls the configuration of the # audisp-ids plugin. active = no direction = out path = /usr/sbin/audisp-ids type = always args = 1 format = string audit-userspace-4.0.5/audisp/plugins/ids/avl.c000066400000000000000000000304511501761310600212740ustar00rootroot00000000000000#include "config.h" #include // for NULL #include "avl.h" // Note: this file is based on this: // https://github.com/firehol/netdata/blob/master/src/avl.c // c63bdb5 on Oct 23, 2017 // // which has been moved to here (05/23/20): // https://github.com/netdata/netdata/blob/master/libnetdata/avl/avl.c // // However, its been modified to remove pthreads as this application will // only use it from a single thread. /* ------------------------------------------------------------------------- */ /* * avl_insert(), avl_remove() and avl_search() * are adaptations (by Costa Tsaousis) of the AVL algorithm found in libavl * v2.0.3, so that they do not use any memory allocations and their memory * footprint is optimized (by eliminating non-necessary data members). * * libavl - library for manipulation of binary trees. * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 Free Software * Foundation, Inc. * GNU Lesser General Public License */ /* Search |tree| for an item matching |item|, and return it if found. Otherwise return |NULL|. */ avl_t *avl_search(const avl_tree_t *tree, avl_t *item) { avl_t *p; // assert (tree != NULL && item != NULL); for (p = tree->root; p != NULL; ) { int cmp = tree->compar(item, p); if (cmp < 0) p = p->avl_link[0]; else if (cmp > 0) p = p->avl_link[1]; else /* |cmp == 0| */ return p; } return NULL; } /* Inserts |item| into |tree| and returns a pointer to |item|'s address. If a duplicate item is found in the tree, returns a pointer to the duplicate without inserting |item|. */ avl_t *avl_insert(avl_tree_t *tree, avl_t *item) { avl_t *y, *z; /* Top node to update balance factor, and parent. */ avl_t *p, *q; /* Iterator, and parent. */ avl_t *n; /* Newly inserted node. */ avl_t *w; /* New root of rebalanced subtree. */ unsigned char dir; /* Direction to descend. */ unsigned char da[AVL_MAX_HEIGHT]; /* Cached comparison results. */ int k = 0; /* Number of cached results. */ // assert(tree != NULL && item != NULL); z = (avl_t *) &tree->root; y = tree->root; dir = 0; for (q = z, p = y; p != NULL; q = p, p = p->avl_link[dir]) { int cmp = tree->compar(item, p); if (cmp == 0) return p; if (p->avl_balance != 0) z = q, y = p, k = 0; da[k++] = dir = (cmp > 0); } n = q->avl_link[dir] = item; // tree->avl_count++; n->avl_link[0] = n->avl_link[1] = NULL; n->avl_balance = 0; if (y == NULL) return n; for (p = y, k = 0; p != n; p = p->avl_link[da[k]], k++) if (da[k] == 0) p->avl_balance--; else p->avl_balance++; if (y->avl_balance == -2) { avl_t *x = y->avl_link[0]; if (x->avl_balance == -1) { w = x; y->avl_link[0] = x->avl_link[1]; x->avl_link[1] = y; x->avl_balance = y->avl_balance = 0; } else { // assert (x->avl_balance == +1); w = x->avl_link[1]; x->avl_link[1] = w->avl_link[0]; w->avl_link[0] = x; y->avl_link[0] = w->avl_link[1]; w->avl_link[1] = y; if (w->avl_balance == -1) x->avl_balance = 0, y->avl_balance = +1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == +1| */ x->avl_balance = -1, y->avl_balance = 0; w->avl_balance = 0; } } else if (y->avl_balance == +2) { avl_t *x = y->avl_link[1]; if (x->avl_balance == +1) { w = x; y->avl_link[1] = x->avl_link[0]; x->avl_link[0] = y; x->avl_balance = y->avl_balance = 0; } else { // assert (x->avl_balance == -1); w = x->avl_link[0]; x->avl_link[0] = w->avl_link[1]; w->avl_link[1] = x; y->avl_link[1] = w->avl_link[0]; w->avl_link[0] = y; if (w->avl_balance == +1) x->avl_balance = 0, y->avl_balance = -1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == -1| */ x->avl_balance = +1, y->avl_balance = 0; w->avl_balance = 0; } } else return n; z->avl_link[y != z->avl_link[0]] = w; // tree->avl_generation++; return n; } /* Deletes from |tree| and returns an item matching |item|. Returns a null pointer if no matching item found. */ avl_t *avl_remove(avl_tree_t *tree, avl_t *item) { /* Stack of nodes. */ avl_t *pa[AVL_MAX_HEIGHT]; /* Nodes. */ unsigned char da[AVL_MAX_HEIGHT]; /* |avl_link[]| indexes. */ int k; /* Stack pointer. */ avl_t *p; /* Traverses tree to find node to delete. */ int cmp; /* Result of comparison between |item| and |p|. */ // assert (tree != NULL && item != NULL); k = 0; p = (avl_t *) &tree->root; for(cmp = -1; cmp != 0; cmp = tree->compar(item, p)) { unsigned char dir = (unsigned char)(cmp > 0); pa[k] = p; da[k++] = dir; p = p->avl_link[dir]; if(p == NULL) return NULL; } item = p; if (p->avl_link[1] == NULL) pa[k - 1]->avl_link[da[k - 1]] = p->avl_link[0]; else { avl_t *r = p->avl_link[1]; if (r->avl_link[0] == NULL) { r->avl_link[0] = p->avl_link[0]; r->avl_balance = p->avl_balance; pa[k - 1]->avl_link[da[k - 1]] = r; da[k] = 1; pa[k++] = r; } else { avl_t *s; int j = k++; for (;;) { da[k] = 0; pa[k++] = r; s = r->avl_link[0]; if (s->avl_link[0] == NULL) break; r = s; } s->avl_link[0] = p->avl_link[0]; r->avl_link[0] = s->avl_link[1]; s->avl_link[1] = p->avl_link[1]; s->avl_balance = p->avl_balance; pa[j - 1]->avl_link[da[j - 1]] = s; da[j] = 1; pa[j] = s; } } // assert (k > 0); while (--k > 0) { avl_t *y = pa[k]; if (da[k] == 0) { y->avl_balance++; if (y->avl_balance == +1) break; else if (y->avl_balance == +2) { avl_t *x = y->avl_link[1]; if (x->avl_balance == -1) { avl_t *w; // assert (x->avl_balance == -1); w = x->avl_link[0]; x->avl_link[0] = w->avl_link[1]; w->avl_link[1] = x; y->avl_link[1] = w->avl_link[0]; w->avl_link[0] = y; if (w->avl_balance == +1) x->avl_balance = 0, y->avl_balance = -1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == -1| */ x->avl_balance = +1, y->avl_balance = 0; w->avl_balance = 0; pa[k - 1]->avl_link[da[k - 1]] = w; } else { y->avl_link[1] = x->avl_link[0]; x->avl_link[0] = y; pa[k - 1]->avl_link[da[k - 1]] = x; if (x->avl_balance == 0) { x->avl_balance = -1; y->avl_balance = +1; break; } else x->avl_balance = y->avl_balance = 0; } } } else { y->avl_balance--; if (y->avl_balance == -1) break; else if (y->avl_balance == -2) { avl_t *x = y->avl_link[0]; if (x->avl_balance == +1) { avl_t *w; // assert (x->avl_balance == +1); w = x->avl_link[1]; x->avl_link[1] = w->avl_link[0]; w->avl_link[0] = x; y->avl_link[0] = w->avl_link[1]; w->avl_link[1] = y; if (w->avl_balance == -1) x->avl_balance = 0, y->avl_balance = +1; else if (w->avl_balance == 0) x->avl_balance = y->avl_balance = 0; else /* |w->avl_balance == +1| */ x->avl_balance = -1, y->avl_balance = 0; w->avl_balance = 0; pa[k - 1]->avl_link[da[k - 1]] = w; } else { y->avl_link[0] = x->avl_link[1]; x->avl_link[1] = y; pa[k - 1]->avl_link[da[k - 1]] = x; if (x->avl_balance == 0) { x->avl_balance = +1; y->avl_balance = -1; break; } else x->avl_balance = y->avl_balance = 0; } } } } // tree->avl_count--; // tree->avl_generation++; return item; } /* ------------------------------------------------------------------------- */ // below are functions by (C) Costa Tsaousis // --------------------------- // traversing int avl_walker(avl_t *node, int (*callback)(void *entry, void *data), void *data) { int total = 0, ret = 0; if(node->avl_link[0]) { ret = avl_walker(node->avl_link[0], callback, data); if(ret < 0) return ret; total += ret; } ret = callback(node, data); if(ret < 0) return ret; total += ret; if(node->avl_link[1]) { ret = avl_walker(node->avl_link[1], callback, data); if (ret < 0) return ret; total += ret; } return total; } int avl_traverse(const avl_tree_t *t, int (*callback)(void *entry, void *data), void *data) { if(t->root) return avl_walker(t->root, callback, data); else return 0; } void avl_init(avl_tree_t *t, int (*compar)(void *a, void *b)) { t->root = NULL; t->compar = compar; } /* ------------------------------------------------------------------------- */ // below are functions by (C) Steve Grubb // --------------------------- avl_t *avl_first(avl_iterator *i, avl_tree_t *t) { if (t->root == NULL || i == NULL) return NULL; i->tree = t; i->height = 0; // follow the leftmost node to its bottom avl_t *node = t->root; while (node->avl_link[0]) { i->stack[i->height] = node; i->height++; node = node->avl_link[0]; } i->current = node; return node; } avl_t *avl_next(avl_iterator *i) { if (i == NULL || i->tree == NULL) return NULL; avl_t *node = i->current; if (node == NULL) return avl_first(i, i->tree); else if (node->avl_link[1]) { i->stack[i->height] = node; i->height++; node = node->avl_link[1]; while (node->avl_link[0]) { i->stack[i->height] = node; i->height++; node = node->avl_link[0]; } } else { avl_t *tmp; do { if (i->height == 0) { i->current = NULL; return NULL; } tmp = node; i->height--; node = i->stack[i->height]; } while (tmp == node->avl_link[1]); } i->current = node; return node; } static int avl_walker2(avl_t *node, avl_tree_t *haystack) { int ret; // If the lefthand has a link, take it so that we walk to the // leftmost bottom if(node->avl_link[0]) { ret = avl_walker2(node->avl_link[0], haystack); if (ret) return ret; } // Next, check the current node avl_t *res = avl_search(haystack, node); if (res) return 1; // If the righthand has a link, take it so that we check all the // rightmost nodes, too. if(node->avl_link[1]) { ret = avl_walker2(node->avl_link[1], haystack); if (ret) return ret; } // nothing found return 0; } int avl_intersection(const avl_tree_t *needle, avl_tree_t *haystack) { // traverse the needle and search the haystack // this implies that needle should be smaller than haystack if (needle && haystack && needle->root && haystack->root) return avl_walker2(needle->root, haystack); // something is not initialized, so we cannot search return 0; } audit-userspace-4.0.5/audisp/plugins/ids/avl.h000066400000000000000000000037131501761310600213020ustar00rootroot00000000000000#ifndef AVL_HEADER #define AVL_HEADER #include "gcc-attributes.h" /* Maximum AVL tree height. */ #ifndef AVL_MAX_HEIGHT #define AVL_MAX_HEIGHT 92 #endif /* Data structures */ /* One element of the AVL tree */ typedef struct avl { struct avl *avl_link[2]; /* Subtrees - 0 left, 1 right */ signed char avl_balance; /* Balance factor. */ } avl_t; /* An AVL tree */ typedef struct avl_tree { avl_t *root; int (*compar)(void *a, void *b); } avl_tree_t; /* Iterator state struct */ typedef struct avl_iterator { avl_tree_t *tree; avl_t *current; avl_t *stack[AVL_MAX_HEIGHT]; unsigned height; } avl_iterator; /* Public methods */ /* Insert element a into the AVL tree t * returns the added element a, or a pointer the * element that is equal to a (as returned by t->compar()) * a is linked directly to the tree, so it has to * be properly allocated by the caller. */ avl_t *avl_insert(avl_tree_t *t, avl_t *a) NEVERNULL WARNUNUSED; /* Remove an element a from the AVL tree t * returns a pointer to the removed element * or NULL if an element equal to a is not found * (equal as returned by t->compar()) */ avl_t *avl_remove(avl_tree_t *t, avl_t *a) WARNUNUSED; /* Find the element into the tree that equal to a * (equal as returned by t->compar()) * returns NULL is no element is equal to a */ avl_t *avl_search(const avl_tree_t *t, avl_t *a); /* Initialize the avl_tree_t */ void avl_init(avl_tree_t *t, int (*compar)(void *a, void *b)); /* Walk the tree and call callback at each node */ int avl_traverse(const avl_tree_t *t, int (*callback)(void *entry, void *data), void *data); /* Walk the tree down to the first node and return it */ avl_t *avl_first(avl_iterator *i, avl_tree_t *t); /* Walk the tree to the next logical node and return it */ avl_t *avl_next(avl_iterator *i); /* Given two trees, see if any in needle are contained in haystack */ int avl_intersection(const avl_tree_t *needle, avl_tree_t *haystack); #endif /* avl.h */ audit-userspace-4.0.5/audisp/plugins/ids/gcc-attributes.h000066400000000000000000000005221501761310600234330ustar00rootroot00000000000000/* gcc-attributes.h -- * * Authors: * Steve Grubb * */ #ifndef GCC_ATTRIBUTES_H #define GCC_ATTRIBUTES_H #define NEVERNULL __attribute__ ((returns_nonnull)) #define WARNUNUSED __attribute__ ((warn_unused_result)) #define MALLOCLIKE __attribute__ ((malloc)) #define NORETURN __attribute__ ((noreturn)) #endif audit-userspace-4.0.5/audisp/plugins/ids/ids.c000066400000000000000000000166701501761310600213000ustar00rootroot00000000000000/* ids.c -- * Copyright 202-25 Steve Grubb. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include #include // umask #include #include #include "auparse.h" #include "libaudit.h" #include "common.h" // FIXME temporary #include "ids.h" #include "ids_config.h" #include "origin.h" #include "account.h" #include "session.h" #include "model_bad_event.h" #include "model_behavior.h" #include "timer-services.h" /* Global Data */ int debug = 1; // mode 3 == file, mode 2 == syslog, 1 == stderr, 0 == nothing int mode = 0; /* Local Data */ static FILE *l = NULL; // Log file static volatile int stop = 0; static volatile int hup = 0; static volatile int dump_state = 0; static auparse_state_t *au = NULL; #define NO_ACTIONS (!hup && !stop && !dump_state) #define STATE_FILE "/var/run/ids-state" #define TIMER_INTERVAL 30 // Run every 30 seconds struct ids_conf config; /* Local declarations */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); void my_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (mode == 2) vsyslog(LOG_WARNING, fmt, ap); else if (mode == 1) { vfprintf(stderr, fmt, ap); fputc('\n', stderr); } else if (mode == 3) { if (l == NULL) { l = fopen("/var/run/audisp-ids.log", "wt"); if (l == NULL) { va_end(ap); return; } setlinebuf(l); } vfprintf(l, fmt, ap); fputc('\n', l); } va_end(ap); } static int audit_fd = -1; static void init_audit(void) { audit_fd = audit_open(); if (audit_fd < 0) { syslog(LOG_ERR, "Cannot open audit connection"); exit(1); } } static void destroy_audit(void) { audit_close(audit_fd); } int log_audit_event(int type, const char *text, int res) { return audit_log_user_message(audit_fd, type, text, NULL, NULL, NULL, res); } /* * SIGTERM handler */ static void term_handler(int sig __attribute__((unused))) { stop = 1; } static void child_handler(int sig __attribute__((unused))) { int status; while (waitpid(-1, &status, WNOHANG)>0) ; /* empty */ } /* * SIGHUP handler: re-read config */ static void hup_handler(int sig __attribute__((unused))) { hup = 1; } static void reload_config(void) { hup = 0; free_config(&config); load_config(&config); } static void sigusr1_handler(int sig __attribute__((unused))) { dump_state = 1; } static void output_state(void) { FILE *f = fopen(STATE_FILE, "wt"); dump_state = 0; if (f) { char *metrics = auparse_metrics(au); if (metrics) { fprintf(f, "auparse\n=======\n"); fprintf(f, "%s\n\n", metrics); free(metrics); } traverse_origins(f); fprintf(f, "\n"); traverse_accounts(f); fprintf(f, "\n"); traverse_sessions(f); dump_config(&config, f); fclose(f); } } int main(void) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; struct sigaction sa; struct itimerspec itval; int tfd; fd_set read_mask; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = child_handler; sigaction(SIGCHLD, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = sigusr1_handler; sigaction(SIGUSR1, &sa, NULL); (void) umask(0177); if (load_config(&config)) return 1; init_audit(); // Initialize the model init_origins(); init_accounts(); init_sessions(); /* Initialize the auparse library */ au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { my_printf("ids is exiting due to auparse init errors"); return -1; } auparse_set_eoe_timeout(2); auparse_add_callback(au, handle_event, NULL, NULL); init_timer_services(); tfd = timerfd_create (CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); if (tfd < 0) { my_printf("ids is exiting due to timerfd_create failing"); return -1; } itval.it_interval.tv_sec = TIMER_INTERVAL; itval.it_interval.tv_nsec = 0; itval.it_value.tv_sec = itval.it_interval.tv_sec; itval.it_value.tv_nsec = 0; timerfd_settime(tfd, 0, &itval, NULL); do { int retval; /* Handle dump_state */ if (dump_state) output_state(); /* Load configuration */ if (hup) reload_config(); /* Probably not needed, but maybe reload took some time? */ if (stop) break; do { FD_ZERO(&read_mask); FD_SET(0, &read_mask); FD_SET(tfd, &read_mask); if (auparse_feed_has_data(au)) { // We'll do a 1 second timeout to try to // age events as quick as possible struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; //my_printf("auparse_feed_has_data"); retval= select(tfd+1, &read_mask, NULL, NULL, &tv); } else retval= select(tfd+1, &read_mask, NULL, NULL, NULL); /* If we timed out & have events, shake them loose */ if (retval == 0 && auparse_feed_has_data(au)) { //my_printf("auparse_feed_age_events"); auparse_feed_age_events(au); } } while (retval == -1 && errno == EINTR && NO_ACTIONS); /* Now the event loop */ if (NO_ACTIONS && retval > 0) { if (FD_ISSET(0, &read_mask)) { do { int len; if ((len = audit_fgets(tmp, MAX_AUDIT_MESSAGE_LENGTH, 0)) > 0) { /* char *buf = strndup(tmp, 40); my_printf("auparse_feed %s", buf); free(buf); */ auparse_feed(au, tmp, len); } } while (audit_fgets_more( MAX_AUDIT_MESSAGE_LENGTH)); } if (FD_ISSET(tfd, &read_mask)) { //my_printf("do_timer_services"); do_timer_services(TIMER_INTERVAL, tfd); } } if (audit_fgets_eof()) break; } while (stop == 0); shutdown_timer_services(); close(tfd); /* Flush any accumulated events from queue */ auparse_flush_feed(au); auparse_destroy(au); destroy_sessions(); destroy_accounts(); destroy_origins(); destroy_audit(); free_config(&config); if (stop) my_printf("ids is exiting on stop request"); else my_printf("ids is exiting on stdin EOF"); if (l) fclose(l); return 0; } /* This function receives a single complete event from the auparse library. */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data __attribute__((unused))) { if (cb_event_type != AUPARSE_CB_EVENT_READY) return; //my_printf("handle_event %s", auparse_get_type_name(au)); /* Do this once for all models */ if (auparse_normalize(au, NORM_OPT_NO_ATTRS)) my_printf("Error normalizing %s", auparse_get_type_name(au)); /* Check for events that are known bad */ process_bad_event_model(au, &config); /* Check if user doing something strange */ process_behavior_model(au, &config); } audit-userspace-4.0.5/audisp/plugins/ids/ids.conf000066400000000000000000000005771501761310600220020ustar00rootroot00000000000000option_origin_failed_logins_threshold = 6 option_origin_failed_logins_reaction = block_address option_session_badness1_threshold = 8 option_session_badness1_reaction = block_address option_service_login_allowed = 0 option_service_login_weight = 7 option_root_login_allowed = 0 option_root_login_weight = 7 option_bad_login_weight = 1 block_address_time = 12h lock_account_time = 20m audit-userspace-4.0.5/audisp/plugins/ids/ids.h000066400000000000000000000005661501761310600213020ustar00rootroot00000000000000/* ids.h -- * * Authors: * Steve Grubb * */ #ifndef IDS_HEADER #define IDS_HEADER #include "libaudit.h" #define DAEMON_SESSION "4294967295" #define UNSET 4294967295 extern int debug; extern void my_printf(const char *fmt, ...) __attribute__ (( format(printf, 1, 2) )); extern int log_audit_event(int type, const char *text, int res); #endif audit-userspace-4.0.5/audisp/plugins/ids/ids_config.c000066400000000000000000000327501501761310600226220ustar00rootroot00000000000000/* model_bad_event.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include /* O_NOFOLLOW needs gnu defined */ #include /* INT_MAX */ #include #include #include "ids_config.h" #include "common.h" #define CONFIG_FILE "/etc/audit/ids.conf" extern char *audit_strsplit(char *s); /* Local prototypes */ struct nv_pair { const char *name; const char *value; }; struct kw_pair { const char *name; int (*parser)(struct nv_pair *, int, struct ids_conf *); }; struct kw_value { const char *name; int value; }; struct nv_list { const char *name; int option; }; static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file) __attr_access ((__write_only__, 2, 3)); static int nv_split(char *buf, struct nv_pair *nv); static const struct kw_pair *kw_lookup(const char *val); static int option_origin_failed_logins_threshold_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_origin_failed_logins_reaction_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_session_badness1_threshold_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_session_badness1_reaction_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_service_login_allowed_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_service_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_root_login_allowed_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_root_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int option_bad_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int block_address_time_parser(struct nv_pair *nv, int line, struct ids_conf *config); static int lock_account_time_parser(struct nv_pair *nv, int line, struct ids_conf *config); static const struct kw_value reactions[] = { { "ignore", REACTION_IGNORE }, { "log", REACTION_LOG }, { "email", REACTION_EMAIL }, { "term_process", REACTION_TERMINATE_PROCESS }, { "term_session", REACTION_TERMINATE_SESSION }, { "restrict_role", REACTION_RESTRICT_ROLE }, { "password_reset", REACTION_PASSWORD_RESET }, { "lock_account_timed", REACTION_LOCK_ACCOUNT_TIMED }, { "lock_account", REACTION_LOCK_ACCOUNT }, { "block_address_timed", REACTION_BLOCK_ADDRESS_TIMED }, { "block_address", REACTION_BLOCK_ADDRESS }, { "system_reboot", REACTION_SYSTEM_REBOOT }, { "system_single_user", REACTION_SYSTEM_SINGLE_USER }, { "system_halt", REACTION_SYSTEM_HALT }, }; #define REACTION_NAMES (sizeof(reactions)/sizeof(reactions[0])) static const struct kw_pair keywords[] = { {"option_origin_failed_logins_threshold", option_origin_failed_logins_threshold_parser }, {"option_origin_failed_logins_reaction", option_origin_failed_logins_reaction_parser }, {"option_session_badness1_threshold", option_session_badness1_threshold_parser }, {"option_session_badness1_reaction", option_session_badness1_reaction_parser }, {"option_service_login_allowed", option_service_login_allowed_parser }, {"option_service_login_weight", option_service_login_weight_parser }, {"option_root_login_allowed", option_root_login_allowed_parser }, {"option_root_login_weight", option_root_login_weight_parser }, {"option_bad_login_weight", option_bad_login_weight_parser }, {"block_address_time", block_address_time_parser }, {"lock_account_time", lock_account_time_parser }, }; void reset_config(struct ids_conf *config) { config->option_origin_failed_logins_threshold = 8; config->option_origin_failed_logins_reaction = REACTION_BLOCK_ADDRESS; config->option_session_badness1_threshold = 8; config->option_session_badness1_reaction = REACTION_TERMINATE_SESSION; config->option_service_login_allowed = 0; config->option_service_login_weight = 5; config->option_root_login_allowed = 0; config->option_root_login_weight = 5; config->option_bad_login_weight = 1; config->block_address_time = 12 * HOURS; config->lock_account_time = 20 * MINUTES; } void free_config(struct ids_conf *config __attribute__((unused))) { } void dump_config(struct ids_conf *config, FILE *f) { fprintf(f, "\nInternal Configuration\n"); fprintf(f, "======================\n"); fprintf(f, "option_origin_failed_logins_threshold: %u\n", config->option_origin_failed_logins_threshold); fprintf(f, "option_session_badness1_threshold: %u\n", config->option_session_badness1_threshold); fprintf(f, "option_service_login_allowed: %u\n", config->option_service_login_allowed); fprintf(f, "option_service_login_weight: %u\n", config->option_service_login_weight); fprintf(f, "option_root_login_allowed: %u\n", config->option_root_login_allowed); fprintf(f, "option_root_login_weight: %u\n", config->option_root_login_weight); fprintf(f, "option_bad_login_weight: %u\n", config->option_bad_login_weight); fprintf(f, "block_address_time: %u\n", config->block_address_time); fprintf(f, "lock_account_time: %u\n", config->lock_account_time); } int load_config(struct ids_conf *config) { int fd, rc, mode, lineno = 1; struct stat st; FILE *f; char buf[160]; reset_config(config); /* open the file */ mode = O_RDONLY; rc = open(CONFIG_FILE, mode); if (rc < 0) { if (errno != ENOENT) { syslog(LOG_ERR, "Error opening config file (%s)", strerror(errno)); return 1; } syslog(LOG_WARNING, "Config file %s doesn't exist, skipping", CONFIG_FILE); return 0; } fd = rc; if (fstat(fd, &st) < 0) { syslog(LOG_ERR, "Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { syslog(LOG_ERR, "Error - %s isn't owned by root", CONFIG_FILE); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { syslog(LOG_ERR, "Error - %s is world writable", CONFIG_FILE); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { syslog(LOG_ERR, "Error - %s is not a regular file", CONFIG_FILE); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { syslog(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf, sizeof(buf), &lineno, CONFIG_FILE)) { // convert line into name-value pair const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. syslog(LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, CONFIG_FILE); break; case 2: // no '=' sign syslog(LOG_ERR, "Missing equal sign for line %d in %s", lineno, CONFIG_FILE); break; default: // something else went wrong... syslog(LOG_ERR, "Unknown error for line %d in %s", lineno, CONFIG_FILE); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); syslog(LOG_ERR, "Not processing any more lines in %s", CONFIG_FILE); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { syslog(LOG_ERR, "Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, CONFIG_FILE); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(&nv, lineno, config); if (rc != 0) { fclose(f); return 1; // local parser puts message out } lineno++; } fclose(f); // if (lineno > 1) // return sanity_check(config); return 0; } static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file) { int too_long = 0; while (fgets_unlocked(buf, size, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) { if (!too_long) { *ptr = 0; return buf; } // Reset and start with the next line too_long = 0; *lineno = *lineno + 1; } else { // If a line is too long skip it. // Only output 1 warning if (!too_long) syslog(LOG_ERR, "Skipping line %d in %s: too long", *lineno, file); too_long = 1; } } return NULL; } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr; nv->name = NULL; nv->value = NULL; ptr = audit_strsplit(buf); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; nv->value = ptr; /* See if there's more */ ptr = audit_strsplit(NULL); if (ptr) return 1; /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int unsigned_int_parser(struct nv_pair *nv, int line, unsigned int *val) { const char *ptr = nv->value; unsigned long i; /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { syslog(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { syslog(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (i > INT_MAX) { syslog(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } *val = (unsigned int)i; return 0; } static int reaction_parser(struct nv_pair *nv, int line, unsigned int *val) { unsigned int i, found = 0; char *ptr, *tmp = strdup(nv->value), *saved; if (tmp == NULL) return 1; *val = 0; ptr = strtok_r(tmp, ",", &saved); while (ptr) { for (i = 0; i < REACTION_NAMES; i++) { if (strcasecmp(reactions[i].name, ptr) == 0) { *val |= (unsigned int)reactions[i].value; found = 1; } } ptr = strtok_r(NULL, ",", &saved); } free(tmp); if (found) return 0; syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int option_origin_failed_logins_threshold_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_origin_failed_logins_threshold); } static int option_origin_failed_logins_reaction_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return reaction_parser(nv, line, &config->option_origin_failed_logins_reaction); } static int option_session_badness1_threshold_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_session_badness1_threshold); } static int option_session_badness1_reaction_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return reaction_parser(nv, line, &config->option_session_badness1_reaction); } static int option_service_login_allowed_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_service_login_allowed); } static int option_service_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_service_login_weight); } static int option_root_login_allowed_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_root_login_allowed); } static int option_root_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_root_login_weight); } static int option_bad_login_weight_parser(struct nv_pair *nv, int line, struct ids_conf *config) { return unsigned_int_parser(nv, line, &config->option_bad_login_weight); } static int block_address_time_parser(struct nv_pair *nv, int line, struct ids_conf *config) { char *end; unsigned long i; errno = 0; i = strtoul(nv->value, &end, 10); if (errno || nv->value == end) { syslog(LOG_ERR, "Error converting %s to a number - line %d", nv->value, line); return 1; } if (*end && end[1]) { syslog(LOG_ERR, "Unexpected characters in %s - line %d", nv->value, line); return 1; } switch (*end) { case 'm': i *= MINUTES; break; case 'h': i *= HOURS; break; case 'd': i *= DAYS; break; case 'M': i *= MONTHS; break; case '\0': break; default: syslog(LOG_ERR, "Unknown time unit in %s - line %d", nv->value, line); return 1; } // Set an arbitrary limit of 500 days if (i > (500 * DAYS)) { syslog(LOG_ERR, "block_address_time = %s exceeds the max of 500 days - line %d", nv->value, line); return 1; } config->block_address_time = (unsigned int)i; return 0; } static int lock_account_time_parser(struct nv_pair *nv, int line, struct ids_conf *config) { long i; i = time_string_to_seconds(nv->value, "ids", line); if (i < 0) return 1; if (i > (500 * DAYS)) { syslog(LOG_ERR, "lock_account_time = %s exceeds the max of 500 days - line %d", nv->value, line); return 1; } config->lock_account_time = (unsigned int)i; return 0; } audit-userspace-4.0.5/audisp/plugins/ids/ids_config.h000066400000000000000000000034661501761310600226310ustar00rootroot00000000000000/* ids_config.h -- * * Authors: * Steve Grubb * */ #ifndef IDS_CONFIG_HEADER #define IDS_CONFIG_HEADER #include // Notifications #define REACTION_IGNORE 0x0000001 #define REACTION_LOG 0x0000002 #define REACTION_EMAIL 0x0000004 // Bad process defenses #define REACTION_TERMINATE_PROCESS 0x0000010 // freeze process? // Bad session defenses #define REACTION_TERMINATE_SESSION 0x0000100 // Account defenses #define REACTION_RESTRICT_ROLE 0x0001000 #define REACTION_PASSWORD_RESET 0x0002000 #define REACTION_LOCK_ACCOUNT_TIMED 0x0004000 #define REACTION_LOCK_ACCOUNT 0x0008000 // drop supplemental groups? // Remote system defenses #define REACTION_BLOCK_ADDRESS_TIMED 0x0010000 #define REACTION_BLOCK_ADDRESS 0x0020000 // System defenses // sysctls, selinux booleans // update specific rpm, all rpms // restart service // drop service timed <- check this against list of things that can't be dropped // System terminations // Drop network timed #define REACTION_SYSTEM_REBOOT 0x2000000 #define REACTION_SYSTEM_SINGLE_USER 0x4000000 #define REACTION_SYSTEM_HALT 0x8000000 struct ids_conf { unsigned int option_origin_failed_logins_threshold; unsigned int option_origin_failed_logins_reaction; unsigned int option_session_badness1_threshold; unsigned int option_session_badness1_reaction; unsigned int option_service_login_allowed; unsigned int option_service_login_weight; unsigned int option_root_login_allowed; unsigned int option_root_login_weight; unsigned int option_bad_login_weight; unsigned int block_address_time; unsigned int lock_account_time; }; extern struct ids_conf config; int load_config(struct ids_conf *config); void reset_config(struct ids_conf *config); void free_config(struct ids_conf *config); void dump_config(struct ids_conf *config, FILE *f); #endif audit-userspace-4.0.5/audisp/plugins/ids/model_bad_event.c000066400000000000000000000102311501761310600236130ustar00rootroot00000000000000/* model_bad_event.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include // inet_pton #include #include #include #include "ids.h" #include "session.h" #include "origin.h" #include "model_bad_event.h" #include "reactions.h" /* Local Data */ static void terminate_sessions(void) { if (get_num_sessions() == 0) return; if (debug) my_printf("terminating all sessions"); // Might want to do more than this like update persistent scores destroy_sessions(); } // Look at the acct, is it a daemon acct and forbidden // Is the acct root and forbidden // is it a bad login // is it a new session static void start_session(auparse_state_t *au, struct ids_conf *config) { unsigned int a; const char *addr = auparse_find_field(au, "addr"); if (addr && *addr != '?') inet_pton(AF_INET, addr, &a); else a = -1; int service_acct = 0; const char *acct = NULL; const char *atype = auparse_normalize_subject_kind(au); if (atype && strncmp(atype, "service", 7) == 0) service_acct = 1; if (auparse_normalize_subject_primary(au) == 1) acct = strdup(auparse_interpret_field(au)); // Have we seen this endpoint before? origin_data_t *o = find_origin(a); if (o == NULL) { new_origin(a); o = find_origin(a); } // Is this login a service account? if (service_acct && !config->option_service_login_allowed) { my_printf("bad_service_login_origin: %s", acct); bad_service_login_origin(o, config, acct); } // Is this a root login else if (!config->option_root_login_allowed && acct && strcmp(acct, "root") == 0) { my_printf("watched_login_origin: %s", acct); watched_login_origin(o, config, acct); } // Check if it's a failed login if (auparse_normalize_get_results(au) == 1) { // Handle a bad login const char *res = auparse_interpret_field(au); if (res && strcmp(res, "failed") == 0) { // Since the login failed, we don't need to // start a new session bad_login_origin(o, config); free((void *)acct); return; } } // Look for new login sessions if (auparse_normalize_session(au) == 1) { unsigned int s = auparse_get_field_int(au); if (s != UNSET) { // new_session takes custody of acct new_session(s, a, acct); acct = NULL; // otherwise we have a strange daemon login } else if (debug) my_printf("start_session: can't find session in serial %s", auparse_get_type_name(au)); } free((void *)acct); } static void end_session(auparse_state_t *au) { if (auparse_normalize_session(au) == 1) { const char *ses = auparse_get_field_str(au); if (ses && strcmp(ses, DAEMON_SESSION)) { unsigned int s = auparse_get_field_int(au); del_session(s); } } } /* This function receives a single complete event from the auparse library. */ void process_bad_event_model(auparse_state_t *au, struct ids_conf *config) { unsigned int answer = 0; auparse_first_record(au); int type = auparse_get_type(au); /* Now we can branch based on what the first record type we find. */ switch (type) { case AUDIT_SYSTEM_BOOT: case AUDIT_SYSTEM_SHUTDOWN: // Reset everything terminate_sessions(); break; // FIXME: update this list as events are added case AUDIT_ANOM_LOGIN_SERVICE: case AUDIT_ANOM_LOGIN_ACCT: // Do not process our own events break; case AUDIT_ANOM_LOGIN_FAILURES: { // Do not process our own events const char *exe = auparse_normalize_how(au); if (exe && strcmp(exe, "/usr/sbin/audisp-ids") == 0) break; } // fallthrough if pam related case AUDIT_ANOM_LOGIN_TIME: case AUDIT_ANOM_LOGIN_SESSIONS: case AUDIT_ANOM_LOGIN_LOCATION: // watch for pam discovered problems break; case AUDIT_USER_LOGIN: start_session(au, config); break; // case AUDIT_USER_END: user_end can be for su case AUDIT_USER_LOGOUT: end_session(au); break; default: break; } // We only mess with origins because it could be a bad login origin_data_t *o = current_origin(); if (o) { if (o->karma >= config->option_origin_failed_logins_threshold && !o->blocked) { //AUDIT_ANOM_ORIGIN_FAILURES answer |= config->option_origin_failed_logins_reaction; do_reaction(answer, "login_failures"); } } } audit-userspace-4.0.5/audisp/plugins/ids/model_bad_event.h000066400000000000000000000003021501761310600236160ustar00rootroot00000000000000#ifndef MODEL_BAD_EVENT_HEADER #define MODEL_BAD_EVENT_HEADER #include "auparse.h" #include "ids_config.h" void process_bad_event_model(auparse_state_t *au, struct ids_conf *config); #endif audit-userspace-4.0.5/audisp/plugins/ids/model_behavior.c000066400000000000000000000062551501761310600234760ustar00rootroot00000000000000/* model_behavior.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include "ids.h" #include "session.h" #include "origin.h" #include "model_behavior.h" #include "reactions.h" /* Local Data */ static void process_plain_syscalls(auparse_state_t *au) { if (auparse_normalize_key(au) == 1) { uint32_t s = -2; const char *key = auparse_interpret_field(au); // If its a key we don't care about, skip it. if (strncmp(key, "ids-", 4)) return; if (auparse_normalize_session(au) == 1) { const char *ses = auparse_get_field_str(au); if (ses && strcmp(ses, DAEMON_SESSION)) s = auparse_get_field_int(au); } // For now, do not process daemon events if ((int32_t)s < 0) return; session_data_t *sess = find_session(s); if (sess) { if (strcmp(key, "ids-recon") == 0) { add_to_score_session(sess, 2); } else if (strcmp(key, "ids-archive") == 0) { add_to_score_session(sess, 5); } else if (strcmp(key, "ids-mkexec") == 0) { add_to_score_session(sess, 4); } else if (strcmp(key, "ids-connections") == 0) { add_to_score_session(sess, 6); } } } } static void process_anomalies(auparse_state_t *au) { if (auparse_normalize_session(au) == 1) { const char *ses = auparse_get_field_str(au); if (ses && strcmp(ses, DAEMON_SESSION)) { unsigned int s = auparse_get_field_int(au); session_data_t *sess = find_session(s); if (sess) { auparse_first_record(au); int type = auparse_get_type(au); if (type == AUDIT_FANOTIFY) add_to_score_session(sess, 12); else add_to_score_session(sess, 2); } } } } /* This function receives a single complete event from the auparse library. */ void process_behavior_model(auparse_state_t *au, struct ids_conf *config) { unsigned int answer = 0; auparse_first_record(au); int type = auparse_get_type(au); /* Now we can branch based on what the first record type we find. */ switch (type) { case AUDIT_SYSCALL: process_plain_syscalls(au); break; //case SECCOMP: case AUDIT_FANOTIFY: case AUDIT_AVC: case AUDIT_ANOM_PROMISCUOUS: case AUDIT_ANOM_ABEND: case AUDIT_ANOM_LINK: // Handle these by looking for session. If // not in a session handle by process process_anomalies(au); break; case AUDIT_USER_MGMT: case AUDIT_ADD_USER: case AUDIT_DEL_USER: case AUDIT_ADD_GROUP: case AUDIT_DEL_GROUP: case AUDIT_GRP_MGMT: break; case AUDIT_USER_AUTH: case AUDIT_USER_ACCT: case AUDIT_GRP_AUTH: // watch for failures in auth break; default: break; } origin_data_t *o = current_origin(); session_data_t *s = current_session(); if (o && s) { if (s->score >= config->option_session_badness1_threshold && s->killed == 0) { //AUDIT_ANOM_SESSION answer |= config->option_session_badness1_reaction; do_reaction(answer, "session_bad"); if (s->killed >= 1) add_to_score_origin(o, 5); else add_to_score_origin(o, 2); } } if (o && o->karma >= config->option_origin_failed_logins_threshold && !o->blocked) { //AUDIT_ANOM_ORIGIN_FAILURES answer |= config->option_origin_failed_logins_reaction; do_reaction(answer, "failed_login"); } } audit-userspace-4.0.5/audisp/plugins/ids/model_behavior.h000066400000000000000000000002771501761310600235010ustar00rootroot00000000000000#ifndef MODEL_BEHAVIOR_HEADER #define MODEL_BEHAVIOR_HEADER #include "auparse.h" #include "ids_config.h" void process_behavior_model(auparse_state_t *au, struct ids_conf *config); #endif audit-userspace-4.0.5/audisp/plugins/ids/nvpair.c000066400000000000000000000047711501761310600220170ustar00rootroot00000000000000/* * nvpair.c - Minimal linked list library for arg-jobue pairs * Copyright (c) 2019 Steve Grubb. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include "nvpair.h" void nvpair_list_create(nvlist *l) { l->head = NULL; l->cur = NULL; l->prev = NULL; l->cnt = 0; } /*nvnode *nvlist_next(nvlist *l) { if (l->cur == NULL) { l->prev = NULL; return NULL; } l->prev = l->cur; l->cur = l->cur->next; return l->cur; }*/ int nvpair_list_append(nvlist *l, nvnode *node) { nvnode* newnode = malloc(sizeof(nvnode)); if (newnode == NULL) return 1; newnode->arg = node->arg; newnode->job = node->job; newnode->expiration = node->expiration; newnode->next = NULL; // if we are at top, fix this up if (l->head == NULL) { l->head = newnode; l->prev = NULL; } else { // Add pointer to newnode and make sure we are at the end while (l->cur->next) { l->prev = l->cur; l->cur = l->cur->next; } l->cur->next = newnode; } // make newnode current l->cur = newnode; l->cnt++; return 0; } int nvpair_list_find_job(nvlist *l, time_t t) { nvnode* node = l->head; l->prev = NULL; while (node) { if (node->expiration <= t) { l->cur = node; return 1; } else { l->prev = node; node = node->next; } } return 0; } void nvpair_list_delete_cur(nvlist *l) { if (l->cur == NULL) return; if (l->cur == l->head) { l->head = l->cur->next; l->prev = NULL; } else if (l->prev) l->prev->next = l->cur->next; free(l->cur->arg); free(l->cur); l->cnt--; } void nvpair_list_clear(nvlist* l) { nvnode* nextnode; nvnode* current; current = l->head; while (current) { nextnode=current->next; free(current->arg); free(current); current=nextnode; } l->head = NULL; l->prev = NULL; l->cur = NULL; l->cnt = 0; } audit-userspace-4.0.5/audisp/plugins/ids/nvpair.h000066400000000000000000000040061501761310600220130ustar00rootroot00000000000000/* * nvpair.h - Header file for ausearch-nvpair.c * Copyright (c) 2019 Steve Grubb. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUNVPAIR_HEADER #define AUNVPAIR_HEADER #include #include #include "timer-services.h" /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _nvnode{ jobs_t job; // The job to run char *arg; // The argument string time_t expiration; // The time when the job can be run struct _nvnode *next; // Next nvpair node pointer } nvnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { nvnode *head; // List head nvnode *cur; // Pointer to current node nvnode *prev; // Pointer to previous node unsigned int cnt; // How many items in this list } nvlist; void nvpair_list_create(nvlist *l); static inline void nvlist_first(nvlist *l) { l->cur = l->head; } //nvnode *nvlist_next(nvlist *l); static inline nvnode *nvpair_list_get_cur(nvlist *l) { return l->cur; } int nvpair_list_append(nvlist *l, nvnode *node); void nvpair_list_delete_cur(nvlist *l); void nvpair_list_clear(nvlist* l); /* Given a time, find a job to run. */ int nvpair_list_find_job(nvlist *l, time_t t); #endif audit-userspace-4.0.5/audisp/plugins/ids/origin.c000066400000000000000000000116161501761310600220030ustar00rootroot00000000000000/* origin.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include "ids.h" #include "origin.h" #include "reactions.h" // This holds info about all sessions struct origin_avl{ avl_tree_t index; unsigned int count; }; static struct origin_avl origins; static origin_data_t *cur = NULL; static int cmp_origins(void *a, void *b) { return (((origin_data_t *)a)->address - ((origin_data_t *)b)->address); } void init_origins(void) { origins.count = 0; cur = NULL; avl_init(&origins.index, cmp_origins); } unsigned int get_num_origins(void) { return origins.count; } static int dump_origin(void *entry, void *data) { FILE *f = data; origin_data_t *o = entry; fprintf(f, "\n"); fprintf(f, " address: %s\n", sockint_to_ipv4(o->address)); fprintf(f, " karma: %u\n", o->karma); fprintf(f, " blocked: %u\n", o->blocked); return 0; } void traverse_origins(FILE *f) { fprintf(f, "Origins\n"); fprintf(f, "=======\n"); fprintf(f, "count: %u\n", origins.count); avl_traverse(&origins.index, dump_origin, f); } static void free_origin(origin_data_t *o) { if (debug) my_printf("Origin freeing %p", o); free(o); } void new_origin(unsigned int a) { origin_data_t *tmp = (origin_data_t *)malloc(sizeof(origin_data_t)); if (tmp) { tmp->address = a; tmp->karma = 0; tmp->blocked = 0; add_origin(tmp); } } static void destroy_origin(void) { avl_t *cur = origins.index.root; origin_data_t *o = (origin_data_t *)avl_remove(&origins.index, cur); if ((avl_t *)o != cur) my_printf("origin: removal of invalid node"); // Now free any data pointed to by cur free_origin(o); cur = NULL; } void destroy_origins(void) { while (origins.index.root) { origins.count--; destroy_origin(); } } int add_origin(origin_data_t *o) { origin_data_t *tmp; if (debug) my_printf("Adding origin %u", o->address); cur = NULL; tmp = (origin_data_t *)avl_insert(&origins.index, (avl_t *)(o)); if (tmp) { if (tmp != o) { if (debug) my_printf("origin: duplicate address found"); free(o); return 1; } origins.count++; cur = tmp; } else if (debug) my_printf("origin: failed inserting address %u", o->address); return 0; } origin_data_t *find_origin(unsigned int addr) { origin_data_t tmp; tmp.address = addr; cur = (origin_data_t *)avl_search(&origins.index, (avl_t *) &tmp); return cur; } origin_data_t *current_origin(void) { return cur; } int del_origin(unsigned int addr) { origin_data_t tmp1, *tmp2; tmp1.address = addr; if (debug) my_printf("Deleting %u", addr); cur = NULL; tmp2 = (origin_data_t *)avl_remove(&origins.index, (avl_t *) &tmp1); if (tmp2) { origins.count--; if (tmp2->address != addr) { if (debug) my_printf("origin: deleting unknown address"); return 1; } } else { if (debug) my_printf("origin: didn't find address"); return 1; } // Now free any data pointed to by tmp2 free_origin(tmp2); return 0; } char *sockint_to_ipv4(unsigned int addr) { unsigned char *uaddr = (unsigned char *)&(addr); static char buf[16]; snprintf(buf, sizeof(buf), "%u.%u.%u.%u", uaddr[0], uaddr[1], uaddr[2], uaddr[3]); return buf; } unsigned int ipv4_to_sockint(const char *buf) { unsigned int addr; unsigned int ip[4] = {0, 0, 0, 0}; if (sscanf(buf, "%u.%u.%u.%u", &ip[3], &ip[2], &ip[1], &ip[0]) != 4) return 0; addr = ip[0] << 24 | ip[1] << 16 | ip[2] << 8 | ip[3]; return addr; } void bad_login_origin(origin_data_t *o, struct ids_conf *config) { // We will just add a 1 for a bad login. add_to_score_origin(o, config->option_bad_login_weight); } void bad_service_login_origin(origin_data_t *o, struct ids_conf *config, const char *acct) { // We will just add a 5 for a bad service login. char buf[62]; const char *addr = sockint_to_ipv4(o->address); // account names can be up to 32 characters. IPv4 can be 16 snprintf(buf, sizeof(buf), "acct=%.32s daddr=%.16s", acct ? acct : "?", addr); log_audit_event(AUDIT_ANOM_LOGIN_SERVICE, buf, 1); add_to_score_origin(o, config->option_service_login_weight); } void watched_login_origin(origin_data_t *o, struct ids_conf *config, const char *acct) { // We will just add a 5 for a watched login. char buf[62]; const char *addr = sockint_to_ipv4(o->address); snprintf(buf, sizeof(buf), "acct=%.32s daddr=%.16s", acct ? acct : "?", addr); log_audit_event(AUDIT_ANOM_LOGIN_ACCT, buf, 1); add_to_score_origin(o, config->option_root_login_weight); } void add_to_score_origin(origin_data_t *o, unsigned int adj) { cur = o; if (o == NULL) { if (debug) my_printf("origin NULL adding score"); return; } o->karma += adj; if (debug) my_printf("origin karma: %u", o->karma); } // Returns 1 on success and 0 on failure int unblock_origin(const char *addr) { unsigned int uaddr = ipv4_to_sockint(addr); origin_data_t *o = find_origin(uaddr); if (o) { o->blocked = 0; return 1; } return 0; } audit-userspace-4.0.5/audisp/plugins/ids/origin.h000066400000000000000000000021331501761310600220020ustar00rootroot00000000000000/* origin.h -- * * Authors: * Steve Grubb * */ #ifndef ORIGIN_HEADER #define ORIGIN_HEADER #include #include "avl.h" #include "ids_config.h" typedef struct origin_data { avl_t avl; // This has to be first unsigned int address; // This hack works for IPv4 unsigned int karma; unsigned int blocked; } origin_data_t; void init_origins(void); void new_origin(unsigned int a); void destroy_origins(void); unsigned int get_num_origins(void); void traverse_origins(FILE *f); int add_origin(origin_data_t *o); origin_data_t *find_origin(unsigned int addr); origin_data_t *current_origin(void); int del_origin(unsigned int addr); void bad_login_origin(origin_data_t *o, struct ids_conf *config); void bad_service_login_origin(origin_data_t *o, struct ids_conf *config, const char *acct); void watched_login_origin(origin_data_t *o, struct ids_conf *config, const char *acct); void add_to_score_origin(origin_data_t *o, unsigned int adj); int unblock_origin(const char *addr); char *sockint_to_ipv4(unsigned int addr); unsigned int ipv4_to_sockint(const char *buf); #endif audit-userspace-4.0.5/audisp/plugins/ids/reactions.c000066400000000000000000000174351501761310600225100ustar00rootroot00000000000000/* reactions.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include // nanosleep #include #include #include #include "ids.h" #include "ids_config.h" #include "reactions.h" #include "session.h" #include "timer-services.h" #include "account.h" #include "common.h" //#include "auparse.h" // Returns 0 on success and 1 on failure static int safe_exec(const char *exe, ...) { char **argv; va_list ap; unsigned int i; int pid; struct sigaction sa; if (exe == NULL) { syslog(LOG_ALERT, "Safe_exec passed NULL for program to execute"); return 1; } pid = fork(); if (pid < 0) { syslog(LOG_ALERT, "Audit IDS failed to fork doing safe_exec"); return 1; } if (pid) /* Parent */ return 0; // FIXME: should we waitpid to know if it succeeded? /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); va_start(ap, exe); for (i = 1; va_arg(ap, char *) != NULL; i++); va_end(ap); argv = alloca(i * sizeof(char *)); va_start(ap, exe); argv[0] = (char *) exe; for (i = 1; (argv[i] = (char *) va_arg(ap, char *)) != NULL; i++); va_end(ap); argv[i] = NULL; execve(exe, argv, NULL); syslog(LOG_ALERT, "Audit IDS failed to exec %s", exe); exit(1); } static void minipause(void) { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 120 * 1000 * 1000; // 120 milliseconds nanosleep(&ts, NULL); } int kill_process(pid_t pid) { if (pid <= 0) return 1; if (debug) my_printf("reaction kill -KILL %d", pid); return kill(pid, SIGKILL); } int kill_session(int session) { char ses[16]; // Do not kill session -1 or the system will die if (session < 0) return 1; snprintf(ses, sizeof(ses), "%d", session); if (debug) my_printf("reaction killall -d %s", ses); return safe_exec("/usr/bin/killall", "-d", ses, NULL); } static int uid_min = -1; static void read_uid_min(void) { FILE *f; char buf[100]; int uid = -1; if (uid_min > 0) return; f = fopen("/etc/login.defs", "r"); if (f == NULL) return; __fsetlocking(f, FSETLOCKING_BYCALLER); while (fgets(buf, sizeof(buf), f)) { if (memcmp(buf, "UID_MIN", 7) == 0) { if (sscanf(buf, "UID_MIN %d", &uid) == 1) { if (uid != -1) { uid_min = uid; if (debug) my_printf("uid_min set to %d", uid_min); } } break; } } fclose(f); } /* returns 0 if user account and 1 on anything else */ static int verify_acct(const char *acct) { struct passwd *pw; if (acct == NULL) return 1; // Make sure valid acct errno = 0; pw = getpwnam(acct); if (pw == NULL || errno) return 1; // Make sure not a daemon if (strstr(pw->pw_shell, "nologin")) return 1; if (uid_min < 0) { read_uid_min(); if (uid_min < 0) return 1; } if ((int)pw->pw_uid < uid_min) return 1; return 0; } int restricted_role(const char *acct) { int rc; if (verify_acct(acct)) return 1; // Restrict to guest user rc = safe_exec("/usr/sbin/semanage", "login", "-m", "-s", "guest_u", acct); if (rc) return rc; // Need to force a logout of all sessions for the user return safe_exec("/usr/bin/killall", "--user", acct); } int force_password_reset(const char *acct) { if (verify_acct(acct)) return 1; return safe_exec("/usr/bin/chage", "-d", "0", acct); } int lock_account(const char *acct) { if (verify_acct(acct)) return 1; return safe_exec("/usr/bin/passwd", "-l", acct); } int unlock_account(const char *acct) { if (verify_acct(acct)) return 1; return safe_exec("/usr/bin/passwd", "-u", acct); } int lock_account_timed(const char *acct, unsigned long length) { int rc = lock_account(acct); if (rc) return rc; return add_timer_job(UNLOCK_ACCOUNT, acct, length); } int block_ip_address(const char *addr) { #ifdef USE_NFTABLES if (debug) my_printf("reaction /sbin/nft add rule inet filter input ip saddr %s drop", addr); minipause(); return safe_exec("/usr/sbin/nft", "add", "rule", "inet", "filter", "input", "ip", "saddr", addr, "drop", NULL); #else if (debug) my_printf("reaction /sbin/iptables -I INPUT -s %s -j DROP", addr); minipause(); return safe_exec("/usr/sbin/iptables", "-I", "INPUT", "-s", addr, "-j","DROP", NULL); #endif } int block_ip_address_timed(const char *addr, unsigned long length) { int rc = block_ip_address(addr); if (rc) return rc; return add_timer_job(UNBLOCK_ADDRESS, addr, length); } static void block_address(unsigned int reaction, const char *reason) { unsigned time_out = config.block_address_time; int res; char buf[80]; origin_data_t *o = current_origin(); const char *addr = sockint_to_ipv4(o->address); if (debug) my_printf("Blocking address %s b/c %s", addr, reason); if (reaction == REACTION_BLOCK_ADDRESS) res = block_ip_address(addr); else res = block_ip_address_timed(addr, time_out); if (res == 0) { o->blocked = 1; if (reaction == REACTION_BLOCK_ADDRESS) { snprintf(buf, sizeof(buf), "daddr=%.16s reason=%s", addr, reason); log_audit_event(AUDIT_RESP_ORIGIN_BLOCK, buf, 1); } else { snprintf(buf, sizeof(buf), "daddr=%.16s reason=%s time_out=%u", addr, reason, time_out/MINUTES); log_audit_event(AUDIT_RESP_ORIGIN_BLOCK_TIMED, buf, 1); } } } int unblock_ip_address(const char *addr) { #ifdef USE_NFTABLES if (debug) my_printf("reaction /sbin/nft delete rule inet filter input ip saddr %s drop", addr); minipause(); return safe_exec("/usr/sbin/nft", "delete", "rule", "inet", "filter", "input", "ip", "saddr", addr, "drop", NULL); #else if (debug) my_printf("reaction /sbin/iptables -D INPUT -s %s -j DROP", addr); minipause(); return safe_exec("/usr/sbin/iptables", "-D", "INPUT", "-s", addr, "-j","DROP", NULL); #endif } int system_reboot(void) { return safe_exec("/sbin/init", "6"); } int system_single_user(void) { return safe_exec("/sbin/init", "1"); } int system_halt(void) { return safe_exec("/sbin/init", "0"); } void do_reaction(unsigned int answer, const char *reason) { //my_printf("Answer: %u", answer); unsigned int num = 0; do { unsigned int tmp = 1 << num; if (answer & tmp) { switch (tmp) { // FIXME: Need to add audit events for these case REACTION_IGNORE: break; // FIXME: do these reactions case REACTION_LOG: case REACTION_EMAIL: break; case REACTION_TERMINATE_PROCESS: {/* auparse_first_record(au); if (auparse_find_field(au, "pid")) { int pid = auparse_get_field_int(au); kill_process(pid); } */} break; case REACTION_TERMINATE_SESSION: { session_data_t *s = current_session(); kill_session(s->session); } break; case REACTION_RESTRICT_ROLE: { account_data_t *a = current_account(); if (a) restricted_role(a->name); } break; case REACTION_PASSWORD_RESET: { account_data_t *a = current_account(); if (a) force_password_reset(a->name); } break; case REACTION_LOCK_ACCOUNT_TIMED: { account_data_t *a = current_account(); if (a) lock_account_timed(a->name, config.lock_account_time); } break; case REACTION_LOCK_ACCOUNT: { account_data_t *a = current_account(); if (a) lock_account(a->name); } break; case REACTION_BLOCK_ADDRESS_TIMED: case REACTION_BLOCK_ADDRESS: block_address(tmp, reason); break; case REACTION_SYSTEM_REBOOT: system_reboot(); break; case REACTION_SYSTEM_SINGLE_USER: system_single_user(); break; case REACTION_SYSTEM_HALT: system_halt(); break; default: if (debug) my_printf("Unknown reaction: %X", tmp); break; } } num++; } while (num < 32); } audit-userspace-4.0.5/audisp/plugins/ids/reactions.h000066400000000000000000000013011501761310600224760ustar00rootroot00000000000000/* reactions.h -- * * Authors: * Steve Grubb * */ #ifndef REACTIONS_HEADER #define REACTIONS_HEADER int kill_process(pid_t pid); int kill_session(int session); int restricted_role(const char *acct); int force_password_reset(const char *acct); int lock_account(const char *acct); int unlock_account(const char *acct); int lock_account_timed(const char *acct, unsigned long length); int block_ip_address(const char *addr); int block_ip_address_timed(const char *addr, unsigned long length); int unblock_ip_address(const char *addr); int system_reboot(void); int system_single_user(void); int system_halt(void); void do_reaction(unsigned int answer, const char *reason); #endif audit-userspace-4.0.5/audisp/plugins/ids/rules/000077500000000000000000000000001501761310600214755ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/ids/rules/25-connections.rules000066400000000000000000000037531501761310600253270ustar00rootroot00000000000000# This rule gets the connections of known data moving programs #-a always,exit -F arch=b64 -S connect,recvfrom -F auid>=1000 -F auid!=-1 -F exe=/usr/bin/awk -F key=ids-connections #-a always,exit -F arch=b64 -S connect,recvfrom -F auid>=1000 -F auid!=-1 -F exe=/usr/bin/bash -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/curl -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/elinks -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ftp -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/git -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/links -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/lynx -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/rsync -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/scp -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/sftp -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ssh -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/w3m -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/wget -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/telnet -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/nc -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ncat -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/nmap -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/nping -F key=ids-connections -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ping -F key=ids-connections audit-userspace-4.0.5/audisp/plugins/ids/rules/25-make-exec.rules000066400000000000000000000021111501761310600246270ustar00rootroot00000000000000# This rule triggers when someone makes an executable in specific directories -a exit,always -F arch=b64 -S chmod,fchmod -F dir=/home -F a1&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S fchmodat -F dir=/home -F a2&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S chmod,fchmod -F dir=/tmp -F a1&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S fchmodat -F dir=/tmp -F a2&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S chmod,fchmod -F dir=/var/tmp -F a1&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S fchmodat -F dir=/var/tmp -F a2&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S chmod,fchmod -F dir=/dev/shm -F a1&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec -a exit,always -F arch=b64 -S fchmodat -F dir=/dev/shm -F a2&0111 -F filetype=file -F auid>=1000 -F auid!=-1 -F key=ids-mkexec audit-userspace-4.0.5/audisp/plugins/ids/rules/25-recon.rules000066400000000000000000000043061501761310600241060ustar00rootroot00000000000000# This set of rules can trigger on events that might be considered recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/uname -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/rpm -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/yum -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/dnf -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/w -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/who -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/whoami -F key=ids-recon #-a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/id -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/netstat -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ss -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/route -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ifconfig -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/ip -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/mount -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/lsof -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/df -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/dig -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/host -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/last -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/lastlog -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/getent -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/history -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/bin/watch -F key=ids-recon -a always,exit -F auid>=1000 -F auid!=-1 -F perm=x -F path=/usr/sbin/sestatus -F key=ids-recon audit-userspace-4.0.5/audisp/plugins/ids/rules/25-unpacking.rules000066400000000000000000000016611501761310600247600ustar00rootroot00000000000000# This rule triggers whenever someone runs a utility that unpacks or in some # instances, packs an archive -a always,exit -F perm=x -F path=/usr/bin/unzip -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/tar -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/bunzip -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/zipgrep -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/gzip -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/gunzip -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/zcat -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/zgrep -F auid>=1000 -F auid!=-1 -F key=ids-archive -a always,exit -F perm=x -F path=/usr/bin/zless -F auid>=1000 -F auid!=-1 -F key=ids-archive audit-userspace-4.0.5/audisp/plugins/ids/rules/Makefile.am000066400000000000000000000020531501761310600235310ustar00rootroot00000000000000# Makefile.am -- # Copyright 2021 Steve Grubb # All Rights Reserved. # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig EXTRA_DIST = 25-connections.rules 25-make-exec.rules 25-recon.rules 25-unpacking.rules rulesdir = $(datadir)/audit-rules/ids-rules dist_rules_DATA = $(EXTRA_DIST) audit-userspace-4.0.5/audisp/plugins/ids/session.c000066400000000000000000000072571501761310600222050ustar00rootroot00000000000000/* session.c -- * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include "ids.h" #include "ids_config.h" #include "origin.h" #include "account.h" #include "session.h" #include "reactions.h" // This holds info about all sessions struct session_avl{ avl_tree_t index; unsigned int count; }; static struct session_avl sessions; static session_data_t *cur = NULL; static int cmp_sessions(void *a, void *b) { return (((session_data_t *)a)->session - ((session_data_t *)b)->session); } void init_sessions(void) { sessions.count = 0; cur = NULL; avl_init(&sessions.index, cmp_sessions); } unsigned int get_num_sessions(void) { return sessions.count; } static int dump_session(void *entry, void *data) { FILE *f = data; session_data_t *s = entry; fprintf(f, "\n"); fprintf(f, " session: %u\n", s->session); fprintf(f, " score: %u\n", s->score); fprintf(f, " killed: %u\n", s->killed); fprintf(f, " origin: %s\n", sockint_to_ipv4(s->origin)); fprintf(f, " acct: %s\n", s->acct); return 0; } void traverse_sessions(FILE *f) { fprintf(f, "Sessions\n"); fprintf(f, "========\n"); fprintf(f, "count: %u\n", sessions.count); avl_traverse(&sessions.index, dump_session, f); } static void free_session(session_data_t *s) { if (debug) my_printf("Freeing session %u, %p", s->session, s); free((void *)s->acct); free((void *)s); } static void destroy_session(void) { avl_t *cur = sessions.index.root; session_data_t *tmp =(session_data_t *)avl_remove(&sessions.index, cur); if ((avl_t *)tmp != cur) my_printf("session: removal of invalid node"); free_session(tmp); cur = NULL; } void new_session(unsigned int s, unsigned int o, const char *acct) { session_data_t *tmp = malloc(sizeof(session_data_t)); if (tmp) { tmp->session = s; tmp->score = 0; tmp->killed = 0; tmp->origin = o; tmp->acct = acct ? acct : strdup(""); add_session(tmp); } } void destroy_sessions(void) { while (sessions.index.root) { sessions.count--; destroy_session(); } } int add_session(session_data_t *s) { session_data_t *tmp; if (debug) my_printf("Adding session %u, %p", s->session, s); cur = NULL; tmp = (session_data_t *)avl_insert(&sessions.index, (avl_t *)(s)); if (tmp) { if (tmp != s) { if (debug) my_printf("session: duplicate session found"); free_session(s); return 1; } sessions.count++; cur = tmp; // Add origin info origin_data_t *o = find_origin(s->origin); if (o == NULL) new_origin(s->origin); // Add account info account_data_t *a = find_account(s->acct); if (a == NULL) new_account(s->acct); return 1; } else if (debug) my_printf("session: failed inserting session %u", s->session); return 0; } session_data_t *find_session(unsigned int s) { session_data_t tmp; tmp.session = s; cur = (session_data_t *)avl_search(&sessions.index, (avl_t *) &tmp); return cur; } session_data_t *current_session(void) { return cur; } int del_session(unsigned int s) { session_data_t tmp1, *tmp2; tmp1.session = s; if (debug) my_printf("Deleting %u", s); cur = NULL; tmp2 = (session_data_t *)avl_remove(&sessions.index, (avl_t *) &tmp1); if (tmp2) { sessions.count--; if (tmp2->session != s) { if (debug) my_printf("session: deleting unknown session"); return 1; } } else { if (debug) my_printf("session: didn't find session"); return 1; } // Now free any data pointed to by tmp2 free_session(tmp2); return 0; } void add_to_score_session(session_data_t *s, unsigned int adj) { cur = s; if (s == NULL) { if (debug) my_printf("session is NULL adding score"); return; } s->score += adj; if (debug) my_printf("session score: %u", s->score); } audit-userspace-4.0.5/audisp/plugins/ids/session.h000066400000000000000000000015511501761310600222010ustar00rootroot00000000000000/* session.h -- * * Authors: * Steve Grubb * */ #ifndef SESSION_HEADER #define SESSION_HEADER #include #include "avl.h" #include "origin.h" #include "ids_config.h" typedef struct session_data { avl_t avl; // This has to be first unsigned int session; unsigned int score; unsigned int killed; unsigned int origin; // This hack works for IPv4 const char *acct; // Not used at the moment } session_data_t; void init_sessions(void); void new_session(unsigned int s, unsigned int o, const char *acct); void destroy_sessions(void); unsigned int get_num_sessions(void); void traverse_sessions(FILE *f); int add_session(session_data_t *s); session_data_t *find_session(unsigned int s); session_data_t *current_session(void); int del_session(unsigned int s); void add_to_score_session(session_data_t *s, unsigned int adj); #endif audit-userspace-4.0.5/audisp/plugins/ids/timer-services.c000066400000000000000000000053471501761310600234610ustar00rootroot00000000000000/* timer-services.c -- * Copyright 2021 Steve Grubb. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include // for snprintf #include // for free #include "timer-services.h" #include "nvpair.h" #include "reactions.h" #include "ids.h" #include "origin.h" static nvlist jobs; static time_t now; // Something to think about, jobs should probably be persistent so that // we can resume them after starting back up. void init_timer_services(void) { nvpair_list_create(&jobs); now = time(NULL); } void do_timer_services(unsigned int interval, int timerfd) { unsigned long long missed = 0; ssize_t r = read(timerfd, &missed, sizeof(missed)); if (r != sizeof(missed) || missed == 0) return; now += interval * missed; // Update with time if the timerfd delta gets too big if (missed > 1 || labs(time(NULL) - now) > (time_t)interval) now = time(NULL); while (nvpair_list_find_job(&jobs, now)) { nvnode *j = nvpair_list_get_cur(&jobs); switch (j->job) { case UNLOCK_ACCOUNT: unlock_account(j->arg); // Should we reset the stats? break; case UNBLOCK_ADDRESS: { // Send firewall rule int res = unblock_ip_address(j->arg); // Log that its back in business char buf[24]; snprintf(buf, sizeof(buf), "daddr=%.16s", j->arg); log_audit_event( AUDIT_RESP_ORIGIN_UNBLOCK_TIMED, buf, !res); // Reset origin state unblock_origin(j->arg); } break; default: break; } nvpair_list_delete_cur(&jobs); } } int add_timer_job(jobs_t job, const char *arg, unsigned long length) { nvnode node; node.job = job; node.expiration = time(NULL) + length; node.arg = strdup(arg); if (node.arg == NULL) { if (debug) my_printf("timer-services: strdup failed adding job"); return 1; } if (nvpair_list_append(&jobs, &node)) { free(node.arg); return 1; } return 0; } void shutdown_timer_services(void) { nvpair_list_clear(&jobs); } audit-userspace-4.0.5/audisp/plugins/ids/timer-services.h000066400000000000000000000022601501761310600234550ustar00rootroot00000000000000/* timer-services.h -- * Copyright 2021 Steve Grubb. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef TIMER_SERVICES_HEADER #define TIMER_SERVICES_HEADER typedef enum {UNLOCK_ACCOUNT, UNBLOCK_ADDRESS} jobs_t; void init_timer_services(void); void do_timer_services(unsigned int interval, int timerfd); int add_timer_job(jobs_t job, const char *arg, unsigned long length); void shutdown_timer_services(void); #endif audit-userspace-4.0.5/audisp/plugins/remote/000077500000000000000000000000001501761310600210575ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/remote/Makefile.am000066400000000000000000000041751501761310600231220ustar00rootroot00000000000000# Makefile.am -- # Copyright 2008-2009,2011,2015,2018 Red Hat Inc. # All Rights Reserved. # # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = au-remote.conf audisp-remote.conf notes.txt $(man_MANS) AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/common prog_confdir = $(sysconfdir)/audit prog_conf = audisp-remote.conf plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = au-remote.conf sbin_PROGRAMS = audisp-remote noinst_HEADERS = remote-config.h queue.h man_MANS = audisp-remote.8 audisp-remote.conf.5 check_PROGRAMS = test-queue TESTS = $(check_PROGRAMS) audisp_remote_DEPENDENCIES = ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la audisp_remote_SOURCES = audisp-remote.c remote-config.c queue.c audisp_remote_CFLAGS = -fPIE -DPIE -g -D_REENTRANT -D_GNU_SOURCE -Wundef ${WFLAGS} audisp_remote_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now audisp_remote_LDADD = $(CAPNG_LDADD) $(gss_libs) ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la test_queue_SOURCES = queue.c test-queue.c install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(prog_conf) ${DESTDIR}${prog_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) rm ${DESTDIR}${prog_confdir}/$(prog_conf) audit-userspace-4.0.5/audisp/plugins/remote/au-remote.conf000066400000000000000000000003551501761310600236270ustar00rootroot00000000000000 # This file controls the auditd data path to the # remote event logger. This plugin will send events to # a remote machine (Central Logger). active = no direction = out path = /sbin/audisp-remote type = always #args = format = string audit-userspace-4.0.5/audisp/plugins/remote/audisp-remote.8000066400000000000000000000025511501761310600237310ustar00rootroot00000000000000.TH AUDISP-REMOTE "8" "August 2018" "Red Hat" "System Administration Utilities" .SH NAME audisp-remote \- plugin for remote logging .SH SYNOPSIS .B audisp-remote .SH DESCRIPTION \fBaudisp-remote\fP is a plugin for the audit event dispatcher that performs remote logging to an aggregate logging server. .SH TIPS If you are aggregating multiple machines, you should edit auditd.conf to set the name_format to something meaningful and the log_format to enriched. This way you can tell where the event came from and have the user name and groups resolved locally before it is sent off of the machine. .SH SIGNALS .TP SIGUSR1 Causes the audisp-remote program to write the value of some of its internal flags to syslog. The .IR suspend flag tells whether or not logging has been suspended. The .IR remote_ended flag tells if the connection was broken by the server saying it can't log events. The .IR transport_ok flag tells whether or not the connection to the remote server is healthy. The .IR queue_size tells how many records are enqueued to be sent to the remote server. .TP SIGUSR2 Causes the audisp-remote program to resume logging if it were suspended due to an error. .SH FILES /etc/audit/audisp-remote.conf /etc/audit/plugins.d/au-remote.conf /etc/audit/auditd.conf .SH "SEE ALSO" .BR auditd.conf (8), .BR auditd-plugins (5), .BR audisp-remote.conf (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/audisp/plugins/remote/audisp-remote.c000066400000000000000000001232031501761310600240020ustar00rootroot00000000000000/* audisp-remote.c -- * Copyright 2008-2012,2016,2018,2019-20 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef USE_GSSAPI #include #include #include #endif #ifdef HAVE_LIBCAP_NG #include #endif #include "libaudit.h" #include "private.h" #include "remote-config.h" #include "queue.h" #define CONFIG_FILE "/etc/audit/audisp-remote.conf" #define BUF_SIZE 32 /* Error types */ #define ET_SUCCESS 0 #define ET_PERMANENT -1 #define ET_TEMPORARY -2 /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static volatile int suspend = 0; static volatile int dump = 0; static volatile int transport_ok = 0; static volatile int sock=-1; // We start with remote_ended true so it retries on startup static volatile int remote_ended = 1, quiet = 0; static int ifd; remote_conf_t config; static int warned = 0; /* Constants */ static const char *SINGLE = "1"; static const char *HALT = "0"; static const char *INIT_PGM = "/sbin/init"; static const char *SPOOL_FILE = "/var/spool/audit/remote.log"; /* Local function declarations */ static int check_message(void); static int relay_event(const char *s, size_t len) __attr_access ((__read_only__, 1, 2)); static int relay_sock(const char *s, size_t len) __attr_access ((__read_only__, 1, 2)); static int relay_sock_managed(const char *s, size_t len) __attr_access ((__read_only__, 1, 2)); static int relay_sock_ascii(const char *s, size_t len) __attr_access ((__read_only__, 1, 2)); static int send_msg_tcp (unsigned char *header, const char *msg, uint32_t mlen) __attr_access ((__read_only__, 2, 3)); static int init_transport(void); static int stop_transport(void); static int ar_read (int, void *, int) __attr_access ((__write_only__, 2, 3)); static int ar_write (int, const void *, int) __attr_access ((__read_only__, 2, 3)); #ifdef USE_GSSAPI /* We only ever talk to one server, so we don't need per-connection credentials. These are the ones we talk to the server with. */ gss_ctx_id_t my_context; #define KEYTAB_NAME "/etc/audit/audisp-remote.key" #define CCACHE_NAME "MEMORY:audisp-remote" #define REQ_FLAGS GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG #define USE_GSS (config.transport == T_KRB5) #endif /* Compile-time expression verification */ #define verify(E) do { \ char verify__[(E) ? 1 : -1]; \ (void)verify__; \ } while (0) /* * SIGTERM handler */ static void term_handler( int sig ) { stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler( int sig ) { hup = 1; } static void reload_config(void) { stop_transport(); // FIXME: We should only stop transport if necessary hup = 0; } /* * SIGSUR1 handler: dump stats */ static void user1_handler( int sig ) { dump = 1; } static void dump_stats(struct queue *queue) { syslog(LOG_INFO, "suspend=%s, remote_ended=%s, transport_ok=%s, queued_items=%zu, queue_depth=%u", suspend ? "yes" : "no", remote_ended ? "yes" : "no", transport_ok ? "yes" : "no", q_queue_length(queue), config.queue_depth); dump = 0; } /* * SIGSUR2 handler: resume logging */ static void user2_handler( int sig ) { suspend = 0; } /* * SIGCHLD handler: reap exiting processes */ static void child_handler(int sig) { while (waitpid(-1, NULL, WNOHANG) > 0) ; /* empty */ } /* * Handlers for various events coming back from the remote server. * Return -1 if the remote dispatcher should exit. */ /* Loss of sync - got an invalid response. */ static int sync_error_handler (const char *why) { /* "why" has human-readable details on why we've lost (or will be losing) sync. Sync errors are transient - if a retry doesn't fix it, we eventually call network_failure_handler which has all the user-tweakable actions. */ syslog (LOG_ERR, "lost/losing sync, %s", why); return 0; } static int is_pipe(int fd) { struct stat st; if (fstat(fd, &st) == 0) { if (S_ISFIFO(st.st_mode)) return 1; } return 0; } static void change_runlevel(const char *level) { char *argv[3]; int pid; // In case of halt, we need to log the message before we halt if (strcmp(level, HALT) == 0) { write_to_console("audit: will try to change runlevel to %s\n", level); } pid = fork(); if (pid < 0) { syslog(LOG_ALERT, "audisp-remote failed to fork switching runlevels"); return; } if (pid) { /* Parent */ int status; // Wait until child exits if (waitpid(pid, &status, 0) < 0) { return; } // Check if child exited normally, runlevel change was successful if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { write_to_console("audit: changed runlevel to %s\n", level); } return; } /* Child */ argv[0] = (char *)INIT_PGM; argv[1] = (char *)level; argv[2] = NULL; execve(INIT_PGM, argv, NULL); syslog(LOG_ALERT, "audisp-remote failed to exec %s", INIT_PGM); exit(1); } static void safe_exec(const char *exe, const char *message) { char *argv[3]; int pid; struct sigaction sa; if (exe == NULL) { syslog(LOG_ALERT, "Safe_exec passed NULL for program to execute"); return; } pid = fork(); if (pid < 0) { syslog(LOG_ALERT, "audisp-remote failed to fork doing safe_exec"); return; } if (pid) /* Parent */ return; /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); argv[0] = (char *)exe; argv[1] = (char *)message; argv[2] = NULL; execve(exe, argv, NULL); syslog(LOG_ALERT, "audisp-remote failed to exec %s", exe); exit(1); } static int do_action (const char *desc, const char *message, int log_level, failure_action_t action, const char *exe) { switch (action) { case FA_IGNORE: return 0; case FA_SYSLOG: syslog (log_level, "%s, %s", desc, message); return 0; case FA_EXEC: safe_exec (exe, message); return 0; case FA_WARN_ONCE_CONT: if (warned & 1) return -1; warned |= 1; syslog (log_level, "%s, %s", desc, message); return 0; case FA_WARN_ONCE: if (warned & 2) return -1; warned |= 2; syslog (log_level, "%s, %s", desc, message); return -1; case FA_SUSPEND: syslog (log_level, "suspending remote logging due to %s", desc); suspend = 1; return -1; case FA_RECONNECT: syslog (log_level, "remote logging disconnected due to %s, will attempt reconnection", desc); return -1; case FA_SINGLE: syslog (log_level, "remote logging is switching system to single user mode due to %s", desc); change_runlevel(SINGLE); return -1; case FA_HALT: syslog (log_level, "remote logging halting system due to %s", desc); change_runlevel(HALT); return -1; case FA_STOP: syslog (log_level, "remote logging stopping due to %s, %s", desc, message); stop = 1; return -1; } syslog (log_level, "unhandled action %d for %s", action, desc); return -1; } static int network_failure_handler (const char *message) { return do_action ("network failure", message, LOG_WARNING, config.network_failure_action, config.network_failure_exe); } static int remote_disk_low_handler (const char *message) { return do_action ("remote server is low on disk space", message, LOG_WARNING, config.disk_low_action, config.disk_low_exe); } static int remote_disk_full_handler (const char *message) { return do_action ("remote server's disk is full", message, LOG_ERR, config.disk_full_action, config.disk_full_exe); } static int remote_disk_error_handler (const char *message) { return do_action ("remote server has a disk error", message, LOG_ERR, config.disk_error_action, config.disk_error_exe); } static int remote_server_ending_handler (const char *message) { stop_transport(); remote_ended = 1; return do_action ("remote server is going down", message, LOG_WARNING, config.remote_ending_action, config.remote_ending_exe); } static int generic_remote_error_handler (const char *message) { return do_action ("unrecognized remote error", message, LOG_ERR, config.generic_error_action, config.generic_error_exe); } static int generic_remote_warning_handler (const char *message) { return do_action ("unrecognized remote warning", message, LOG_WARNING, config.generic_warning_action, config.generic_warning_exe); } /* Report and handle a queue error, using errno. */ static void queue_error(void) { char *errno_str; errno_str = strerror(errno); do_action("queue error", errno_str, LOG_ERR, config.queue_error_action, config.queue_error_exe); } static int startup_failure_handler(const char *message) { return do_action("startup network failure", message, LOG_WARNING, config.startup_failure_action, config.startup_failure_exe); } static void send_heartbeat (void) { relay_event (NULL, 0); } static void do_overflow_action(void) { switch (config.overflow_action) { case OA_IGNORE: break; case OA_SYSLOG: syslog(LOG_ERR, "queue is full - dropping event"); break; case OA_SUSPEND: syslog(LOG_ALERT, "Audisp-remote is suspending event processing due to overflowing its queue."); suspend = 1; break; case OA_SINGLE: syslog(LOG_ALERT, "Audisp-remote is now changing the system to single user mode due to overflowing its queue"); change_runlevel(SINGLE); break; case OA_HALT: syslog(LOG_ALERT, "Audisp-remote is now halting the system due to overflowing its queue"); change_runlevel(HALT); break; default: syslog(LOG_ALERT, "Unknown overflow action requested"); break; } } /* Initialize and return a queue depending on user's configuration. On error return NULL and set errno. */ static struct queue *init_queue(void) { const char *path; int q_flags; if (config.queue_file != NULL) path = config.queue_file; else path = SPOOL_FILE; q_flags = Q_IN_MEMORY; if (config.mode == M_STORE_AND_FORWARD) /* FIXME: let user control Q_SYNC? */ q_flags |= Q_IN_FILE | Q_CREAT | Q_RESIZE; verify(QUEUE_ENTRY_SIZE >= MAX_AUDIT_MESSAGE_LENGTH); return q_open(q_flags, path, config.queue_depth, QUEUE_ENTRY_SIZE); } /* Send a record from QUEUE to the remote system */ static void send_one(struct queue *queue) { char event[MAX_AUDIT_MESSAGE_LENGTH]; int len; if (suspend || !transport_ok) return; len = q_peek(queue, event, sizeof(event)); if (len == 0) return; if (len < 0) { queue_error(); return; } /* We send len -1 to remove trailing \n */ if (relay_event(event, len-1) < 0) return; /* reset on all successful transmissions */ warned = 0; if (q_drop_head(queue) != 0) queue_error(); } int main(int argc, char *argv[]) { struct sigaction sa; struct queue *queue; size_t q_len; int connected_once = 0; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = user1_handler; sigaction(SIGUSR1, &sa, NULL); sa.sa_handler = user2_handler; sigaction(SIGUSR2, &sa, NULL); sa.sa_handler = child_handler; sigaction(SIGCHLD, &sa, NULL); if (load_config(&config, CONFIG_FILE)) return 6; (void) umask( umask( 077 ) | 027 ); // ifd = open("test.log", O_RDONLY); ifd = 0; fcntl(ifd, F_SETFL, O_NONBLOCK); // Start up the queue queue = init_queue(); if (queue == NULL) { syslog(LOG_ERR, "Error initializing audit record queue: %m"); return 1; } #ifdef HAVE_LIBCAP_NG // Drop capabilities capng_clear(CAPNG_SELECT_BOTH); if (config.local_port && config.local_port < 1024) capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_NET_BIND_SERVICE); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "audisp-remote plugin was unable to drop capabilities, continuing with elevated priviles"); #endif syslog(LOG_NOTICE, "Audisp-remote started with queue_size: %zu", q_queue_length(queue)); while (stop == 0) { //FIXME break out when socket is closed fd_set rfd, wfd; struct timeval tv; char event[MAX_AUDIT_MESSAGE_LENGTH]; int n, fds = ifd + 1; /* Load configuration */ if (hup) reload_config(); if (dump) dump_stats(queue); /* Setup select flags */ FD_ZERO(&rfd); FD_SET(ifd, &rfd); // input fd FD_ZERO(&wfd); if (sock >= 0) { // Setup socket to read acks from server FD_SET(sock, &rfd); // remote socket if (sock > ifd) fds = sock + 1; // If we have anything in the queue, // find out if we can send it if (q_queue_length(queue) && !suspend && transport_ok) FD_SET(sock, &wfd); } if (config.format==F_MANAGED && config.heartbeat_timeout>0) { tv.tv_sec = config.heartbeat_timeout; tv.tv_usec = 0; n = select(fds, &rfd, &wfd, NULL, &tv); } else n = select(fds, &rfd, &wfd, NULL, NULL); if (n < 0) continue; // If here, we had some kind of problem if ((config.heartbeat_timeout > 0) && n == 0 && !remote_ended) { /* We attempt a heartbeat if select fails, which * may give us more heartbeats than we need. This * is safer than too few heartbeats. */ if (config.format == F_MANAGED) { quiet = 1; send_heartbeat(); quiet = 0; continue; } } // See if we got a shutdown message from the server if (sock >= 0 && FD_ISSET(sock, &rfd)) check_message(); // If we broke out due to one of these, cycle to start if (hup != 0 || stop != 0) continue; // See if input fd is also set if (FD_ISSET(ifd, &rfd)) { do { if (audit_fgets(event,sizeof(event),ifd) > 0) { if (!transport_ok && remote_ended && (config.remote_ending_action == FA_RECONNECT || !connected_once)) { quiet = 1; if (init_transport() == ET_SUCCESS) { remote_ended = 0; connected_once = 1; } else if (!connected_once) { startup_failure_handler( "First attempt at connecting to server unsuccessful"); } quiet = 0; } /* Strip out EOE records */ if (*event == 't') { if (strncmp(event, "type=EOE", 8) == 0) continue; } else { char *ptr = strchr(event, ' '); if (ptr) { ptr++; if (strncmp(ptr, "type=EOE", 8) == 0) continue; } else continue; //malformed } if (q_append(queue, event) != 0) { if (errno == ENOSPC) do_overflow_action(); else queue_error(); } } else if (audit_fgets_eof()) stop = 1; } while (audit_fgets_more(sizeof(event))); } // See if output fd is also set if (sock >= 0 && FD_ISSET(sock, &wfd)) { // If so, try to drain backlog while (q_queue_length(queue) && !suspend && !stop && transport_ok) send_one(queue); } } // If stdin is a pipe, then flush the queue if (is_pipe(0)) { while (q_queue_length(queue) && !suspend && transport_ok) send_one(queue); } if (sock >= 0) { shutdown(sock, SHUT_RDWR); close(sock); } free_config(&config); q_len = q_queue_length(queue); q_close(queue); if (stop) syslog(LOG_NOTICE, "audisp-remote is exiting on stop request, queue_size: %zu", q_len); return q_len ? 1 : 0; } #ifdef USE_GSSAPI /* Communications under GSS is done by token exchanges. Each "token" may contain a message, perhaps signed, perhaps encrypted. The messages within are what we're interested in, but the network sees the tokens. The protocol we use for transferring tokens is to send the length first, four bytes MSB first, then the token data. We return nonzero on error. */ static int recv_token(int s, gss_buffer_t tok) { int ret; unsigned char lenbuf[4]; unsigned int len; ret = ar_read(s, (char *) lenbuf, 4); if (ret < 0) { syslog(LOG_ERR, "GSS-API error reading token length"); return -1; } else if (!ret) { return 0; } else if (ret != 4) { syslog(LOG_ERR, "GSS-API error reading token length"); return -1; } len = ( ((uint32_t)(lenbuf[0] & 0xFF) << 24) | ((uint32_t)(lenbuf[1] & 0xFF) << 16) | ((uint32_t)(lenbuf[2] & 0xFF) << 8) | (uint32_t)(lenbuf[3] & 0xFF)); if (len > MAX_AUDIT_MESSAGE_LENGTH) { syslog(LOG_ERR, "GSS-API error: event length exceeds MAX_AUDIT_LENGTH"); return -1; } tok->length = len; tok->value = (char *) malloc(tok->length ? tok->length : 1); if (tok->length && tok->value == NULL) { syslog(LOG_ERR, "Out of memory allocating token data %zd %zx", tok->length, tok->length); return -1; } ret = ar_read(s, (char *) tok->value, tok->length); if (ret < 0) { syslog(LOG_ERR, "GSS-API error reading token data"); free(tok->value); return -1; } else if (ret != (int) tok->length) { syslog(LOG_ERR, "GSS-API error reading token data"); free(tok->value); return -1; } return 0; } /* Same here. */ static int send_token(int s, gss_buffer_t tok) { int ret; unsigned char lenbuf[4]; unsigned int len; if (tok->length > 0xffffffffUL) return -1; len = tok->length; lenbuf[0] = (len >> 24) & 0xff; lenbuf[1] = (len >> 16) & 0xff; lenbuf[2] = (len >> 8) & 0xff; lenbuf[3] = len & 0xff; ret = ar_write(s, (char *) lenbuf, 4); if (ret < 0) { syslog(LOG_ERR, "GSS-API error sending token length"); return -1; } else if (ret != 4) { syslog(LOG_ERR, "GSS-API error sending token length"); return -1; } ret = ar_write(s, tok->value, tok->length); if (ret < 0) { syslog(LOG_ERR, "GSS-API error sending token data"); return -1; } else if (ret != (int) tok->length) { syslog(LOG_ERR, "GSS-API error sending token data"); return -1; } return 0; } static void gss_failure_2 (const char *msg, int status, int type) { OM_uint32 message_context = 0; OM_uint32 min_status = 0; gss_buffer_desc status_string; do { gss_display_status (&min_status, status, type, GSS_C_NO_OID, &message_context, &status_string); syslog (LOG_ERR, "GSS error: %s: %s", msg, (char *)status_string.value); gss_release_buffer(&min_status, &status_string); } while (message_context != 0); } static void gss_failure (const char *msg, int major_status, int minor_status) { gss_failure_2 (msg, major_status, GSS_C_GSS_CODE); if (minor_status) gss_failure_2 (msg, minor_status, GSS_C_MECH_CODE); } #define KLOG(x,f) { \ const char *kstr = krb5_get_error_message(kcontext, x); \ syslog (LOG_ERR, "krb5 error: %s in %s\n", kstr, f); \ krb5_free_error_message(kcontext, kstr); } static krb5_context kcontext = NULL; static char *realm_name = NULL; static krb5_principal audit_princ; static krb5_ccache ccache = NULL; static krb5_get_init_creds_opt options; static krb5_keytab keytab = NULL; /* Each time we connect to the server, we negotiate a set of credentials and a security context. To do this, we need our own credentials first. For other Kerberos applications, the user will have called kinit (or otherwise authenticated) first, but we don't have that luxury. So, we implement part of kinit here. When our tickets expire, the usual close/open/retry logic has us calling here again, where we re-init and get new tickets. */ static int negotiate_credentials (void) { gss_buffer_desc empty_token_buf = { 0, (void *) "" }; gss_buffer_t empty_token = &empty_token_buf; gss_buffer_desc send_tok, recv_tok, *token_ptr; gss_ctx_id_t *gss_context = &my_context; gss_buffer_desc name_buf; gss_name_t service_name_e; OM_uint32 major_status, minor_status, init_sec_min_stat; OM_uint32 ret_flags; /* Getting an initial ticket is outside the scope of GSS, so we use Kerberos calls here. */ int krberr; krb5_creds my_creds; const char *krb5_client_name; char *slashptr; char host_name[255]; struct stat st; const char *key_file; token_ptr = GSS_C_NO_BUFFER; *gss_context = GSS_C_NO_CONTEXT; recv_tok.value = NULL; krberr = krb5_init_context (&kcontext); if (krberr) { KLOG (krberr, "krb5_init_context"); return -1; } if (config.krb5_key_file) key_file = config.krb5_key_file; else key_file = KEYTAB_NAME; unsetenv ("KRB5_KTNAME"); setenv ("KRB5_KTNAME", key_file, 1); if (stat (key_file, &st) == 0) { if ((st.st_mode & 07777) != 0400) { if (!quiet) syslog (LOG_ERR, "%s is not mode 0400 (it's %#o) - compromised key?", key_file, st.st_mode & 07777); goto error1; } if (st.st_uid != 0) { if (!quiet) syslog (LOG_ERR, "%s is not owned by root (it's %d) - compromised key?", key_file, st.st_uid); goto error1; } } /* This looks up the default real (*our* realm) from /etc/krb5.conf (or wherever) */ krberr = krb5_get_default_realm (kcontext, &realm_name); if (krberr) { KLOG (krberr, "krb5_get_default_realm"); goto error1; } krb5_client_name = config.krb5_client_name ? config.krb5_client_name : "auditd"; if (gethostname(host_name, sizeof(host_name)) != 0) { if (!quiet) syslog (LOG_ERR, "gethostname: host name longer than %lu characters?", sizeof (host_name)); goto error2; } syslog (LOG_ERR, "kerberos principal: %s/%s@%s\n", krb5_client_name, host_name, realm_name); /* Encode our own "name" as auditd/remote@EXAMPLE.COM. */ krberr = krb5_build_principal (kcontext, &audit_princ, strlen(realm_name), realm_name, krb5_client_name, host_name, NULL); if (krberr) { KLOG (krberr, "krb5_build_principal"); goto error2; } /* Locate our machine's key table, where our private key is * held. */ krberr = krb5_kt_resolve (kcontext, key_file, &keytab); if (krberr) { KLOG (krberr, "krb5_kt_resolve"); goto error3; } /* Identify a cache to hold the key in. The GSS wrappers look up our credentials here. */ krberr = krb5_cc_resolve (kcontext, CCACHE_NAME, &ccache); if (krberr) { KLOG (krberr, "krb5_cc_resolve"); goto error4; } setenv("KRB5CCNAME", CCACHE_NAME, 1); memset(&my_creds, 0, sizeof(my_creds)); memset(&options, 0, sizeof(options)); krb5_get_init_creds_opt_set_address_list(&options, NULL); krb5_get_init_creds_opt_set_forwardable(&options, 0); krb5_get_init_creds_opt_set_proxiable(&options, 0); krb5_get_init_creds_opt_set_tkt_life(&options, 24*60*60); /* Load our credentials from the key table. */ krberr = krb5_get_init_creds_keytab(kcontext, &my_creds, audit_princ, keytab, 0, NULL, &options); if (krberr) { KLOG (krberr, "krb5_get_init_creds_keytab"); goto error5; } /* Create the cache... */ krberr = krb5_cc_initialize(kcontext, ccache, audit_princ); if (krberr) { KLOG (krberr, "krb5_cc_initialize"); goto error5; } /* ...and store our credentials in it. */ krberr = krb5_cc_store_cred(kcontext, ccache, &my_creds); if (krberr) { KLOG (krberr, "krb5_cc_store_cred"); goto error5; } /* The GSS code now has a set of credentials for this program. I.e. we know who "we" are. Now we talk to the server to get its credentials and set up a security context for encryption. */ if (config.krb5_principal == NULL) { const char *name = config.krb5_client_name ? config.krb5_client_name : "auditd"; config.krb5_principal = (char *) malloc (strlen (name) + 1 + strlen (config.remote_server) + 1); sprintf((char *)config.krb5_principal, "%s@%s", name, config.remote_server); } slashptr = strchr (config.krb5_principal, '/'); if (slashptr) *slashptr = '@'; name_buf.value = (char *)config.krb5_principal; name_buf.length = strlen(name_buf.value) + 1; major_status = gss_import_name(&minor_status, &name_buf, (gss_OID) gss_nt_service_name, &service_name_e); if (major_status != GSS_S_COMPLETE) { gss_failure("importing name", major_status, minor_status); goto error5; } /* Someone has to go first. In this case, it's us. */ if (send_token(sock, empty_token) < 0) { (void) gss_release_name(&minor_status, &service_name_e); goto error5; } /* The server starts this loop with the token we just sent (the empty one). We start this loop with "no token". */ token_ptr = GSS_C_NO_BUFFER; *gss_context = GSS_C_NO_CONTEXT; do { /* Give GSS a chance to digest what we have so far. */ major_status = gss_init_sec_context(&init_sec_min_stat, GSS_C_NO_CREDENTIAL, gss_context, service_name_e, NULL, REQ_FLAGS, 0, NULL, /* no channel bindings */ token_ptr, NULL, /* ignore mech type */ &send_tok, &ret_flags, NULL); /* ignore time_rec */ if (token_ptr != GSS_C_NO_BUFFER) free(recv_tok.value); /* Send the server any tokens requested of us. */ if (send_tok.length != 0) { if (send_token(sock, &send_tok) < 0) { (void) gss_release_buffer(&minor_status, &send_tok); (void) gss_release_name(&minor_status, &service_name_e); goto error5; } } (void) gss_release_buffer(&minor_status, &send_tok); if (major_status != GSS_S_COMPLETE && major_status != GSS_S_CONTINUE_NEEDED) { gss_failure("initializing context", major_status, init_sec_min_stat); (void) gss_release_name(&minor_status, &service_name_e); if (*gss_context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, gss_context, GSS_C_NO_BUFFER); goto error5; } /* Now get any tokens the sever sends back. We use these back at the top of the loop. */ if (major_status == GSS_S_CONTINUE_NEEDED) { if (recv_token(sock, &recv_tok) < 0) { (void) gss_release_name(&minor_status, &service_name_e); goto error5; } token_ptr = &recv_tok; } } while (major_status == GSS_S_CONTINUE_NEEDED); (void) gss_release_name(&minor_status, &service_name_e); #if 0 major_status = gss_inquire_context (&minor_status, &my_context, NULL, &service_name_e, NULL, NULL, NULL, NULL, NULL); if (major_status != GSS_S_COMPLETE) { gss_failure("inquiring target name", major_status, minor_status); return -1; } major_status = gss_display_name(&minor_status, service_name_e, &recv_tok, NULL); gss_release_name(&minor_status, &service_name_e); if (major_status != GSS_S_COMPLETE) { gss_failure("displaying name", major_status, minor_status); return -1; } syslog(LOG_INFO, "GSS-API Connected to: %s", (char *)recv_tok.value); #endif return 0; error5: krb5_cc_close(kcontext, ccache); ccache = NULL; error4: krb5_kt_close(kcontext, keytab); keytab = NULL; error3: krb5_free_principal(kcontext, audit_princ); error2: krb5_free_default_realm(kcontext, realm_name); realm_name = NULL; error1: krb5_free_context(kcontext); kcontext = NULL; return -1; } #endif // USE_GSSAPI static int stop_sock(void) { if (sock >= 0) { #ifdef USE_GSSAPI if (USE_GSS) { if (my_context != GSS_C_NO_CONTEXT) { OM_uint32 minor_status; gss_delete_sec_context(&minor_status, &my_context, GSS_C_NO_BUFFER); my_context = GSS_C_NO_CONTEXT; } if (kcontext != NULL) { if (ccache != NULL) { krb5_cc_close(kcontext, ccache); ccache = NULL; } if (keytab != NULL) { krb5_kt_close(kcontext, keytab); keytab = NULL; } if (audit_princ != NULL) { krb5_free_principal(kcontext, audit_princ); audit_princ = NULL; } if (realm_name != NULL) { krb5_free_default_realm(kcontext, realm_name); realm_name = NULL; } krb5_free_context(kcontext); kcontext = NULL; } } #endif shutdown(sock, SHUT_RDWR); close(sock); } sock = -1; transport_ok = 0; return 0; } static int stop_transport(void) { int rc; switch (config.transport) { case T_TCP: case T_KRB5: rc = stop_sock(); break; default: rc = -1; break; } return rc; } static int init_sock(void) { int rc; struct addrinfo *ai, *runp; struct addrinfo hints; char remote[BUF_SIZE]; int one=1; if (sock >= 0) { syslog(LOG_NOTICE, "socket already setup"); transport_ok = 1; return ET_SUCCESS; } // Resolve the remote host memset(&hints, '\0', sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV; hints.ai_socktype = SOCK_STREAM; snprintf(remote, BUF_SIZE, "%u", config.port); rc = getaddrinfo(config.remote_server, remote, &hints, &ai); if (rc) { if (!quiet) syslog(LOG_ERR, "Error looking up remote host: %s - exiting", gai_strerror(rc)); if (rc == EAI_NONAME || rc == EAI_NODATA) return ET_PERMANENT; else return ET_TEMPORARY; } // Cycle through the list until we connect runp = ai; while (runp) { if (sock >= 0) close(sock); sock = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (sock < 0) { if (!quiet) syslog(LOG_ERR, "Error creating socket: %s", strerror(errno)); goto next_try; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int)); // If we are binding, resolve something relative to // the address of the aggregating server if (config.local_port != 0) { struct addrinfo *ai2; struct addrinfo hints2; char local[BUF_SIZE]; // Ask for setting that can be used for bind memset(&hints2, '\0', sizeof(hints2)); hints2.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints2.ai_socktype = SOCK_STREAM; hints2.ai_family = runp->ai_family; hints2.ai_protocol = runp->ai_protocol; snprintf(local, BUF_SIZE, "%u", config.local_port); rc = getaddrinfo(NULL, local, &hints2, &ai2); if (rc) { if (!quiet) syslog(LOG_ERR, "Error looking up local host: %s - retrying", gai_strerror(rc)); stop_sock(); goto next_try; } // We are not going to cycle through the list. // If done right only one should be on list. if (bind(sock, ai2->ai_addr, ai2->ai_addrlen)) { if (!quiet) syslog(LOG_ERR, "Cannot bind local socket to port %u", config.local_port); stop_sock(); freeaddrinfo(ai2); goto next_try; } freeaddrinfo(ai2); } if (connect(sock, runp->ai_addr, runp->ai_addrlen)) { if (!quiet) syslog(LOG_ERR, "Error connecting to %s: %s", config.remote_server, strerror(errno)); stop_sock(); } else break; // Success, quit trying next_try: runp = runp->ai_next; } // If the list was exhausted and no connection, we failed. if (runp == NULL) { rc = ET_PERMANENT; goto out; } rc = ET_SUCCESS; setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int)); /* The idea here is to minimize the time between the message and the ACK, assuming that individual messages are infrequent enough that we can ignore the inefficiency of sending the header and message in separate packets. */ if (config.format == F_MANAGED) setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int)); #ifdef USE_GSSAPI if (USE_GSS) { if (negotiate_credentials()) { rc = ET_PERMANENT; goto out; } } #endif transport_ok = 1; syslog(LOG_NOTICE, "Connected to %s", config.remote_server); out: freeaddrinfo(ai); return rc; } static int init_transport(void) { int rc; switch (config.transport) { case T_TCP: case T_KRB5: rc = init_sock(); // We set this so that it will retry the connection if (rc == ET_TEMPORARY) remote_ended = 1; break; default: rc = ET_PERMANENT; break; } return rc; } static int ar_write (int sk, const void *buf, int len) { int rc = 0, r; while (len > 0) { do { r = write(sk, buf, len); } while (r < 0 && errno == EINTR); if (r < 0) { if (errno == EPIPE) stop_sock(); return r; } if (r == 0) break; rc += r; buf = (void *)((char *)buf + r); len -= r; } return rc; } // Returns positive number on success, -1 on failure static int ar_read (int sk, void *buf, int len) { int rc = 0, r, timeout = config.max_time_per_record * 1000; struct pollfd pfd; errno = 0; pfd.fd = sk; pfd.events = POLLIN | POLLPRI | POLLHUP | POLLERR | POLLNVAL; while (len > 0) { do { // Reads can hang if cable is disconnected int prc = poll(&pfd, (nfds_t) 1, timeout); if (prc <= 0) return -1; r = read(sk, buf, len); } while (r < 0 && errno == EINTR); if (r < 0) { // This means real network problem happened if (errno == EPIPE) stop_sock(); return r; } if (r == 0) { // If errno == 0, remote end closed socket normally if (errno == 0) { stop_sock(); remote_ended = 1; } break; } rc += r; buf = (void *)((char *)buf + r); len -= r; } return rc; } static int relay_sock_ascii(const char *s, size_t len) { int rc; if (len == 0) return 0; if (!transport_ok) { if (init_transport ()) return -1; } rc = ar_write(sock, s, len); if (rc <= 0) { stop = 1; stop_transport(); syslog(LOG_ERR,"Connection to %s closed unexpectedly - exiting", config.remote_server); return -1; } return 0; } #ifdef USE_GSSAPI /* Sending an encrypted message is pretty simple - wrap the message in a token, and send the token. The server unwraps it to get the original message. */ static int send_msg_gss (unsigned char *header, const char *msg, uint32_t mlen) { OM_uint32 major_status, minor_status; gss_buffer_desc utok, etok; int rc; utok.length = AUDIT_RMW_HEADER_SIZE + mlen; utok.value = malloc (utok.length); memcpy (utok.value, header, AUDIT_RMW_HEADER_SIZE); if (msg != NULL && mlen > 0) memcpy (utok.value+AUDIT_RMW_HEADER_SIZE, msg, mlen); major_status = gss_wrap (&minor_status, my_context, 1, GSS_C_QOP_DEFAULT, &utok, NULL, &etok); if (major_status != GSS_S_COMPLETE) { gss_failure("encrypting message", major_status, minor_status); free (utok.value); return -1; } rc = send_token (sock, &etok); free (utok.value); (void) gss_release_buffer(&minor_status, &etok); return rc ? -1 : 0; } /* Likewise here. */ static int recv_msg_gss (unsigned char *header, char *msg, uint32_t *mlen) { OM_uint32 major_status, minor_status; gss_buffer_desc utok, etok; int hver, mver, rc; uint32_t type, rlen, seq; rc = recv_token (sock, &etok); if (rc) return -1; major_status = gss_unwrap (&minor_status, my_context, &etok, &utok, NULL, NULL); if (major_status != GSS_S_COMPLETE) { gss_failure("decrypting message", major_status, minor_status); free (utok.value); free (etok.value); return -1; } if (utok.length < AUDIT_RMW_HEADER_SIZE) { sync_error_handler ("message too short"); free (utok.value); free (etok.value); return -1; } memcpy (header, utok.value, AUDIT_RMW_HEADER_SIZE); if (! AUDIT_RMW_IS_MAGIC (header, AUDIT_RMW_HEADER_SIZE)) { sync_error_handler ("bad magic number"); free (utok.value); free (etok.value); return -1; } AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, rlen, seq); if (rlen > MAX_AUDIT_MESSAGE_LENGTH) { sync_error_handler ("message too long"); free (utok.value); free (etok.value); return -1; } memcpy (msg, utok.value+AUDIT_RMW_HEADER_SIZE, rlen); *mlen = rlen; free (utok.value); free (etok.value); return 0; } #endif // USE_GSSAPI static int send_msg_tcp (unsigned char *header, const char *msg, uint32_t mlen) { int rc; rc = ar_write(sock, header, AUDIT_RMW_HEADER_SIZE); if (rc <= 0) { syslog(LOG_ERR, "send to %s failed", config.remote_server); return 1; } if (msg != NULL && mlen > 0) { rc = ar_write(sock, msg, mlen); if (rc <= 0) { syslog(LOG_ERR, "send to %s failed", config.remote_server); return 1; } } return 0; } // Returns 0 on success and -1 on failure static int recv_msg_tcp (unsigned char *header, char *msg, uint32_t *mlen) { int hver, mver, rc; uint32_t type, rlen, seq; errno = 0; rc = ar_read (sock, header, AUDIT_RMW_HEADER_SIZE); if (rc < 16) { if (rc == -1 && errno == 0) syslog(LOG_ERR, "ack from %s timed out", config.remote_server); else syslog(LOG_ERR, "read from %s failed", config.remote_server); return -1; } if (! AUDIT_RMW_IS_MAGIC (header, AUDIT_RMW_HEADER_SIZE)) { /* FIXME: the right thing to do here is close the socket * and start a new one. */ sync_error_handler ("bad magic number"); return -1; } AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, rlen, seq); if (rlen > MAX_AUDIT_MESSAGE_LENGTH) { sync_error_handler ("message too long"); return -1; } if (rlen > 0 && ar_read (sock, msg, rlen) < rlen) { sync_error_handler ("ran out of data reading reply"); return -1; } return 0; } static int check_message_managed(void) { unsigned char header[AUDIT_RMW_HEADER_SIZE]; int hver, mver; uint32_t type, rlen, seq; char msg[MAX_AUDIT_MESSAGE_LENGTH+1]; #ifdef USE_GSSAPI if (USE_GSS) { if (recv_msg_gss (header, msg, &rlen)) { stop_transport(); return -1; } } else #endif if (recv_msg_tcp(header, msg, &rlen)) { stop_transport(); return -1; } AUDIT_RMW_UNPACK_HEADER(header, hver, mver, type, rlen, seq); msg[rlen] = 0; if (type == AUDIT_RMW_TYPE_ENDING) return remote_server_ending_handler(msg); if (type == AUDIT_RMW_TYPE_DISKLOW) return remote_disk_low_handler(msg); if (type == AUDIT_RMW_TYPE_DISKFULL) { // Can't log for a while might want a delay stop_transport(); return remote_disk_full_handler(msg); } if (type == AUDIT_RMW_TYPE_DISKERROR) { // Can't log for a while might want a delay stop_transport(); return remote_disk_error_handler(msg); } return 0; } /* If this gets called, it most likely means that the remote end died. * We need to try a read to get the EPIPE so that we can close out the * connection. */ static int check_message_ascii(void) { int rc; char buf[64]; rc = ar_read(sock, buf, sizeof(buf)); if (rc < 0 || remote_ended) stop = 1; return 0; } /* This is to check for async notification like server is shutting down */ static int check_message(void) { int rc; switch (config.format) { case F_MANAGED: rc = check_message_managed(); break; case F_ASCII: rc = check_message_ascii(); break; default: rc = -1; break; } return rc; } static int relay_sock_managed(const char *s, size_t len) { static int sequence_id = 1; unsigned char header[AUDIT_RMW_HEADER_SIZE]; int hver, mver; uint32_t type, rlen, seq; char msg[MAX_AUDIT_MESSAGE_LENGTH+1]; unsigned int n_tries_this_message = 0; time_t now, then = 0; sequence_id ++; try_again: time (&now); if (then == 0) then = now; /* We want the first retry to be quick, in case the network failed for some fail-once reason. In this case, it goes "failure - reconnect - send". Only if this quick retry fails do we start pausing between retries to prevent swamping the local computer and the network. */ if (n_tries_this_message > 1) sleep (config.network_retry_time); if (n_tries_this_message > config.max_tries_per_record) { network_failure_handler ("max retries exhausted"); return -1; } if ((now - then) > config.max_time_per_record) { network_failure_handler ("max retry time exhausted"); return -1; } n_tries_this_message ++; if (!transport_ok) { if (init_transport ()) goto try_again; } type = (s != NULL) ? AUDIT_RMW_TYPE_MESSAGE : AUDIT_RMW_TYPE_HEARTBEAT; AUDIT_RMW_PACK_HEADER (header, 0, type, len, sequence_id); #ifdef USE_GSSAPI if (USE_GSS) { if (send_msg_gss (header, s, len)) { stop_transport (); goto try_again; } } else #endif if (send_msg_tcp (header, s, len)) { stop_transport (); goto try_again; } #ifdef USE_GSSAPI if (USE_GSS) { if (recv_msg_gss (header, msg, &rlen)) { stop_transport (); goto try_again; } } else #endif if (recv_msg_tcp (header, msg, &rlen)) { stop_transport (); goto try_again; } AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, rlen, seq); msg[rlen] = 0; /* Handle this first. It doesn't matter if seq compares or not * since the other end is going down...deal with it. */ if (type == AUDIT_RMW_TYPE_ENDING) return remote_server_ending_handler (msg); if (seq != sequence_id) { /* FIXME: should we read another header and see if it matches? If so, we need to deal with timeouts. */ if (sync_error_handler ("mismatched response")) return -1; stop_transport(); goto try_again; } /* Specific errors we know how to deal with. */ if (type == AUDIT_RMW_TYPE_DISKLOW) return remote_disk_low_handler (msg); if (type == AUDIT_RMW_TYPE_DISKFULL) { // Can't log for a while might want a delay stop_transport(); return remote_disk_full_handler (msg); } if (type == AUDIT_RMW_TYPE_DISKERROR) { // Can't log for a while might want a delay stop_transport(); return remote_disk_error_handler (msg); } /* Generic errors. */ if (type & AUDIT_RMW_TYPE_FATALMASK) return generic_remote_error_handler (msg); if (type & AUDIT_RMW_TYPE_WARNMASK) return generic_remote_warning_handler (msg); return 0; } static int relay_sock(const char *s, size_t len) { int rc; switch (config.format) { case F_MANAGED: rc = relay_sock_managed (s, len); break; case F_ASCII: rc = relay_sock_ascii (s, len); break; default: rc = -1; break; } return rc; } /* Send audit event to remote system */ static int relay_event(const char *s, size_t len) { int rc; switch (config.transport) { case T_TCP: case T_KRB5: rc = relay_sock(s, len); break; default: rc = -1; break; } return rc; } audit-userspace-4.0.5/audisp/plugins/remote/audisp-remote.conf000066400000000000000000000013571501761310600245120ustar00rootroot00000000000000# # This file controls the configuration of the audit remote # logging subsystem, audisp-remote. # remote_server = port = 60 ##local_port = transport = tcp queue_file = /var/spool/audit/remote.log mode = immediate queue_depth = 10240 format = managed network_retry_time = 1 max_tries_per_record = 3 max_time_per_record = 5 heartbeat_timeout = 0 network_failure_action = stop disk_low_action = ignore disk_full_action = warn_once disk_error_action = warn_once remote_ending_action = reconnect generic_error_action = syslog generic_warning_action = syslog queue_error_action = stop overflow_action = syslog startup_failure_action = warn_once_continue ##krb5_principal = ##krb5_client_name = auditd ##krb5_key_file = /etc/audisp/audisp-remote.key audit-userspace-4.0.5/audisp/plugins/remote/audisp-remote.conf.5000066400000000000000000000265751501761310600246660ustar00rootroot00000000000000.TH AUDISP-REMOTE.CONF "5" "Jul 2022" "Red Hat" "System Administration Utilities" .SH NAME audisp-remote.conf \- the audisp-remote configuration file .SH DESCRIPTION \fBaudisp-remote.conf\fP is the file that controls the configuration of the audit remote logging subsystem. The options that are available are as follows: .TP .I remote_server This is a one word character string that is the remote server hostname or address that this plugin will send log information to. This can be the numeric address or a resolvable hostname. .TP .I port This option is an unsigned integer that indicates what port to connect to on the remote machine. .TP .I local_port This option is an unsigned integer that indicates what local port to connect from on the local machine. If unspecified (the default) or set to the word .I any then any available unprivileged port is used. This is a security mechanism to prevent untrusted user space apps from injecting events into the audit daemon. You should set it to an unused port < 1024 to ensure that only privileged users can bind to that port. Then also set the tcp_client_ports in the aggregating auditd.conf file to match the ports that clients are sending from. .TP .I transport This parameter tells the remote logging app how to send events to the remote system. The valid options are .IR TCP ", and " KRB5 ". If set to .IR TCP , the remote logging app will just make a normal clear text connection to the remote system. If its set to .IR KRB5 ", then Kerberos 5 will be used for authentication and encryption. The default value is TCP. .TP .I mode This parameter tells the remote logging app what strategy to use getting records to the remote system. Valid values are .IR immediate ", and " forward " . If set to .IR immediate , the remote logging app will attempt to send events immediately after getting them. .I forward means that it will store the events to disk and then attempt to send the records. If the connection cannot be made, it will queue records until it can connect to the remote system. The depth of the queue is controlled by the .I queue_depth option. .TP .I queue_file Path of a file used for the event queue if .I mode is set to \fIforward\fP. The default is \fB/var/spool/audit/remote.log\fP. .TP .I queue_depth This option is an unsigned integer that determines how many records can be buffered to disk or in memory before considering it to be a failure sending. This parameter affects the .I forward mode of the .I mode option and internal queueing for temporary network outages. The default depth is 2048. .TP .I format This parameter tells the remote logging app what data format will be used for the messages sent over the network. The default is .I managed which adds some overhead to ensure each message is properly handled on the remote end, and to receive status messages from the remote server. If .I ascii is given instead, each message is a simple ASCII text line with no overhead at all. The .I ascii format is a very simplistic protocol. If there are any network problems, it will cause audisp-remote to exit. Auditd may or may not restart it on next event. If something more robust is needed, use the .I managed format. If .I mode is set to \fIforward\fP, .I format must be \fImanaged\fP. .TP .I network_retry_time The time, in seconds, between retries when a network error is detected. Note that this pause applies starting after the second attempt, so as to avoid unneeded delays if a reconnect is sufficient to fix the problem. The default is 1 second. .TP .I max_tries_per_record The maximum number of times an attempt is made to deliver each message. The minimum value is one, as even a completely successful delivery requires at least one try. If too many attempts are made, the network_failure_action action is performed. The default is 3. .TP .I max_time_per_record The maximum amount of time, in seconds, spent attempting to deliver each message. Note that both this and .I max_tries_per_record should be set, as each try may take a long time to time out. The default value is 5 seconds. If too much time is used on a message, the network_failure_action action is performed. .TP .I heartbeat_timeout This parameter determines how often in seconds the client should send a heartbeat event to the remote server. This is used to let both the client and server know that each end is alive and has not terminated in a way that it did not shutdown the connection uncleanly. This value must be coordinated with the server's .I tcp_client_max_idle setting. The default value is 0 which disables sending a heartbeat. .TP .I network_failure_action This parameter tells the system what action to take whenever there is an error detected when sending audit events to the remote system. Valid values are .IR ignore ", " syslog ", " exec ", " warn_once ", " suspend ", " single ", " halt ", and " stop . If set to .IR ignore , the remote logging app does nothing. If an event was sent, its dequeued. .I Syslog means that it will issue a warning to syslog. If an event was sent, its dequeued. This is the default. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. If an event was sent, its dequeued. .I warn_once_continue is like syslog except that only one message is put in syslog until an event is successfully transferred. .I warn_once is like warn_once_continue except that the event is not dequeued. .I Suspend will cause the remote logging app to stop sending records to the remote system. The logging app will still be alive. If an event was sent, it is not dequeued. The .I single option will cause the remote logging app to put the computer system in single user mode. If an event was sent, it is not dequeued. The .I stop option will cause the remote logging app to exit, but leave other plugins running. If an event was sent, it is not dequeued. The .I halt option will cause the remote logging app to shutdown the computer system. If an event was sent, it is not dequeued. The default is to stop. .TP .I disk_low_action Likewise, this parameter tells the system what action to take if the remote end signals a disk low error. The default is ignore. .TP .I disk_full_action Likewise, this parameter tells the system what action to take if the remote end signals a disk full error. The default is warn_once. .TP .I disk_error_action Likewise, this parameter tells the system what action to take if the remote end signals a disk error. The default is warn_once. .TP .I remote_ending_action Likewise, this parameter tells the system what action to take if the network connection is lost. This action has one additional option, .I reconnect which tells the remote plugin to attempt to reconnect to the server upon receipt of the next audit record. If an event was being sent when something triggered this action, it is not dequeued. If it is unsuccessful in reconnecting, the audit record could be lost. The default is to reconnect. .TP .I generic_error_action Likewise, this parameter tells the system what action to take if the remote end signals an error we don't recognize. The default is to log it to syslog. .TP .I generic_warning_action Likewise, this parameter tells the system what action to take if the remote end signals a warning we don't recognize. The default is to log it to syslog. .TP .I queue_error_action Likewise, this parameter tells the system what action to take if there is a problem working with a local record queue. The default is stop. .TP .I overflow_action This parameter tells the system what action to take if the internal event queue overflows. Valid values are .IR ignore ", " syslog ", " suspend ", " single ", and " halt " . If set to .IR ignore , the remote logging app does nothing. .I Syslog means that it will issue a warning to syslog. This is the default. .I Suspend will cause the remote logging app to stop sending records to the remote system. The logging app will still be alive. The .I single option will cause the remote logging app to put the computer system in single user mode. The .I halt option will cause the remote logging app to shutdown the computer system. .TP .I startup_failure_action This parameter tells the system what action to take whenever there is an error connecting to the remote system during startup. Typically, this is benign as the plugin's default behavior is to attempt reconnecting until it succeeds. But there may be times when you want to do something different. Valid values are .IR ignore ", " syslog ", " exec ", " warn_once ", and " warn_once_continue " . If set to .IR ignore , the remote logging app does nothing. .I Syslog means that it will issue a warning to syslog. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. .I warn_once is like syslog except that only one message is put in syslog until an event is successfully transferred. .I warn_once_continue is like warn_once except it ignores the problem. This is the default. .TP .I enable_krb5 This option is deprecated. Use the .IR transport option to enable Kerberos support. If this option follows the transport configuration option, it will override the transport setting. This would be the normal expected behavior for backwards compatibility. If set to .IR yes ", Kerberos 5 will be used for authentication and encryption. Default is .IR no ". Note that encryption can only be used with managed connections, not plain ASCII. .TP .I krb5_principal If specified, This is the expected principal for the server. The client and server will use the specified principal to negotiate the encryption. The format for the .I krb5_principal is like somename/hostname, see the auditd.conf man page for details. If not specified, the krb5_client_name and remote_server values are used. .TP .I krb5_client_name This specifies the name portion of the client's own principal. If unspecified, the default is "auditd". The remainder of the principal will consist of the host's fully qualified domain name and the default Kerberos realm, like this: .I auditd/host14.example.com@EXAMPLE.COM (assuming you gave "auditd" as the krb_client_name). Note that the client and server must have the same principal name and realm. .TP .I krb5_key_file Location of the key for this client's principal. Note that the key file must be owned by root and mode 0400. The default is .I /etc/audisp/audisp-remote.key .SH "NOTES" Specifying a local port may make it difficult to restart the audit subsystem due to the previous connection being in a TIME_WAIT state, if you're reconnecting to and from the same hosts and ports as before. The network failure logic works as follows: The first attempt to deliver normally "just works". If it doesn't, a second attempt is immediately made, perhaps after reconnecting to the server. If the second attempt also fails, .I audispd-remote pauses for the configured time and tries again. It continues to pause and retry until either too many attempts have been made or the allowed time expires. Note that these times govern the maximum amount of time the remote server is allowed in order to reboot, if you want to maintain logging across a reboot. It is recommended to set a large q_depth in auditd.conf if using this plugin. Also set an even bigger q_depth in audisp-remote.conf. Also set the heartbeat_timeout to something non-zero but coordinate it with the server so that it's half the size of the server's tcp_client_max_idle setting. This is required to get retries in a reasonable time if the network has a problem. .SH "SEE ALSO" .BR audisp-remote (8), .BR auditd.conf (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/audisp/plugins/remote/notes.txt000066400000000000000000000031051501761310600227470ustar00rootroot00000000000000The queue data structure can keep data only in memory, only on disk (writing it to disk and reading from disk), or in both (writing everything to disk, but reading from disk only data stored in a previous run). audisp-remote will use the last option for performance. The queue file format starts with a fixed header, followed by an array of slots for strings. Due to the fixed size of each slot the file format is rather inefficient, but it is also very simple. The file is preallocated and the string slots will be aligned to a 4KB boundary, so it should be necessary to only write one block to disk when audisp-remote receives a (short) audit record. With the default queue size of 200 items the file will be about 2.4 megabytes large, which is probably not really worth worrying about. If necessary, the space utilization could be improved by storing strings consecutively instead of using pre-arranged slots. The queue file format is intended to be resilient against unexpected termination of the process, and should be resilient against unexpected system crash as long as the OS does not reorder writes (the string data is written before the header that indicates that it is present) - but ultimately resiliency against such failures is limited by other links in the audit record transmission chain - if the record is lost within auditd, having a resilient queue file format does not help; audit records generated within the kernel are necessarily lost if the system crashes before they are read by auditd because the kernel will not be able to regenerate/retransmit them after the next boot. audit-userspace-4.0.5/audisp/plugins/remote/queue.c000066400000000000000000000325071501761310600223560ustar00rootroot00000000000000/* queue.c - a string queue implementation * Copyright 2009, 2011 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "queue.h" struct queue { int flags; /* Q_* */ int fd; /* -1 if !Q_IN_FILE */ /* NULL if !Q_IN_MEMORY. [i] contains a memory copy of the queue entry "i", if known - it may be NULL even if entry exists. */ unsigned char **memory; size_t num_entries; size_t entry_size; size_t queue_head; size_t queue_length; unsigned char buffer[]; /* Used only locally within q_peek() */ }; /* Local Declarations */ static int full_pread(int fd, void *buf, size_t size, off_t offset) __attr_access ((__write_only__, 2, 3)); static int full_pwrite(int fd, const void *buf, size_t size, off_t offset) __attr_access ((__read_only__, 2, 3)); /* Compile-time expression verification */ #define verify(E) do { \ char verify__[(E) ? 1 : -1]; \ (void)verify__; \ } while (0) /* Like pread(), except that it handles partial reads, and returns 0 on success. */ static int full_pread(int fd, void *buf, size_t size, off_t offset) { while (size != 0) { ssize_t run, res; if (size > QUEUE_ENTRY_SIZE) run = QUEUE_ENTRY_SIZE; else run = size; res = pread(fd, buf, run, offset); if (res < 0) return -1; if (res == 0) { errno = ENXIO; /* Any better value? */ return -1; } buf = (unsigned char *)buf + res; size -= res; offset += res; } return 0; } /* Like pwrite(), except that it handles partial writes, and returns 0 on success. */ static int full_pwrite(int fd, const void *buf, size_t size, off_t offset) { while (size != 0) { ssize_t run, res; if (size > QUEUE_ENTRY_SIZE) run = QUEUE_ENTRY_SIZE; else run = size; res = pwrite(fd, buf, run, offset); if (res < 0) return -1; if (res == 0) { errno = ENXIO; /* Any better value? */ return -1; } buf = (const unsigned char *)buf + res; size -= res; offset += res; } return 0; } /* File format and utilities */ /* The mutable part of struct file_header */ struct fh_state { uint32_t queue_head; /* 0-based index of the first non-empty entry */ uint32_t queue_length; /* [0, num_entries] */ }; /* All integer values are in network byte order (big endian) */ struct file_header { uint8_t magic[14]; /* See fh_magic below */ uint8_t version; /* File format version, see FH_VERSION* below */ uint8_t reserved; /* Must be 0 */ /* Total file size is (num_entries + 1) * entry_size. This must fit into SIZE_MAX because the "len" parameter of posix_fallocate has a size_t type. */ uint32_t num_entries; /* Total number of entries allocated */ uint32_t entry_size; struct fh_state s; }; /* Contains a '\0' byte to unambiguously mark the file as a binary file. */ static const uint8_t fh_magic[14] = "\0audisp-remote"; #define FH_VERSION_0 0x00 /* Return file position for ENTRY in Q */ static size_t entry_offset (const struct queue *q, size_t entry) { return (entry + 1) * q->entry_size; } /* Synchronize Q if required and return 0. On error, return -1 and set errno. */ static int q_sync(struct queue *q) { if ((q->flags & Q_SYNC) == 0) return 0; return fdatasync(q->fd); } /* Sync file's fh_state with Q, q_sync (Q), and return 0. On error, return -1 and set errno. */ static int sync_fh_state (struct queue *q) { struct fh_state s; if (q->fd == -1) return 0; s.queue_head = htonl(q->queue_head); s.queue_length = htonl(q->queue_length); if (full_pwrite(q->fd, &s, sizeof(s), offsetof(struct file_header, s)) != 0) return -1; return q_sync(q); } /* Queue implementation */ /* Open PATH for Q, update Q from it, and return 0. On error, return -1 and set errno; Q->fd may be set even on error. */ static int q_open_file(struct queue *q, const char *path) { int open_flags, fd_flags; struct stat st; struct file_header fh; open_flags = O_RDWR; if ((q->flags & Q_CREAT) != 0) open_flags |= O_CREAT; if ((q->flags & Q_EXCL) != 0) open_flags |= O_EXCL; q->fd = open(path, open_flags, S_IRUSR | S_IWUSR); if (q->fd == -1) return -1; fd_flags = fcntl(q->fd, F_GETFD); if (fd_flags < 0) return -1; if (fcntl(q->fd, F_SETFD, fd_flags | FD_CLOEXEC) == -1) return -1; /* File locking in POSIX is pretty much broken... let's hope nobody attempts to open a single file twice within the same process. open() above has initialized the file offset to 0, so the lockf() below affects the whole file. */ if (lockf(q->fd, F_TLOCK, 0) != 0) { if (errno == EACCES || errno == EAGAIN) errno = EBUSY; /* This makes more sense... */ return -1; } if (fstat(q->fd, &st) != 0) return -1; if (st.st_size == 0) { verify(sizeof(fh.magic) == sizeof(fh_magic)); memcpy(fh.magic, fh_magic, sizeof(fh.magic)); fh.version = FH_VERSION_0; fh.reserved = 0; fh.num_entries = htonl(q->num_entries); fh.entry_size = htonl(q->entry_size); fh.s.queue_head = htonl(0); fh.s.queue_length = htonl(0); if (full_pwrite(q->fd, &fh, sizeof(fh), 0) != 0) return -1; if (q_sync(q) != 0) return -1; #ifdef HAVE_POSIX_FALLOCATE if (posix_fallocate(q->fd, 0, (q->num_entries + 1) * q->entry_size) != 0) return -1; #endif } else { uint32_t file_entries; if (full_pread(q->fd, &fh, sizeof(fh), 0) != 0) return -1; if (memcmp(fh.magic, fh_magic, sizeof(fh.magic)) != 0 || fh.version != FH_VERSION_0 || fh.reserved != 0 || fh.entry_size != htonl(q->entry_size)) { errno = EINVAL; return -1; } file_entries = ntohl(fh.num_entries); if (file_entries > SIZE_MAX / q->entry_size - 1 || ((uintmax_t)st.st_size != (file_entries + 1) * q->entry_size)) { errno = EINVAL; return -1; } } /* Note that this may change q->num_entries! */ q->num_entries = ntohl(fh.num_entries); q->queue_head = ntohl(fh.s.queue_head); q->queue_length = ntohl(fh.s.queue_length); if (q->queue_head >= q->num_entries || q->queue_length > q->num_entries) { errno = EINVAL; return -1; } return 0; } /* Like q_open(), but does not handle Q_RESIZE, and NUM_ENTRIES is only used when creating a new file. */ static struct queue *q_open_no_resize(int q_flags, const char *path, size_t num_entries, size_t entry_size) { struct queue *q; int saved_errno; if ((q_flags & (Q_IN_MEMORY | Q_IN_FILE)) == 0) { errno = EINVAL; return NULL; } if (num_entries == 0 || num_entries > UINT32_MAX || entry_size < 1 /* for trailing NUL */ || entry_size < sizeof(struct file_header) /* for Q_IN_FILE */ /* to allocate "struct queue" including its buffer*/ || entry_size > UINT32_MAX - sizeof(struct queue)) { errno = EINVAL; return NULL; } if (entry_size > SIZE_MAX || num_entries > SIZE_MAX / entry_size - 1 /* for Q_IN_FILE */ || num_entries > SIZE_MAX / sizeof(*q->memory)) { errno = EINVAL; return NULL; } q = malloc(sizeof(*q) + entry_size); if (q == NULL) return NULL; q->flags = q_flags; q->fd = -1; q->memory = NULL; q->num_entries = num_entries; q->entry_size = entry_size; q->queue_head = 0; q->queue_length = 0; if ((q_flags & Q_IN_MEMORY) != 0) { size_t sz = num_entries * sizeof(*q->memory); q->memory = malloc(sz); if (q->memory == NULL) goto err; memset(q->memory, 0, sz); } if ((q_flags & Q_IN_FILE) != 0 && q_open_file(q, path) != 0) goto err; return q; err: saved_errno = errno; if (q->fd != -1) close(q->fd); free(q->memory); free(q); errno = saved_errno; return NULL; } void q_close(struct queue *q) { if (q->fd != -1) close(q->fd); /* Also releases the file lock */ if (q->memory != NULL) { size_t i; for (i = 0; i < q->num_entries; i++) free(q->memory[i]); free(q->memory); } free(q); } /* Internal use only: add DATA to Q, but don't update fh_state. */ static int q_append_no_sync_fh_state(struct queue *q, const char *data) { size_t data_size, entry_index; unsigned char *copy; if (q->queue_length == q->num_entries) { errno = ENOSPC; return -1; } data_size = strlen(data) + 1; if (data_size > q->entry_size) { errno = EINVAL; return -1; } entry_index = (q->queue_head + q->queue_length) % q->num_entries; if (q->memory != NULL) { if (q->memory[entry_index] != NULL) { errno = EIO; /* This is _really_ unexpected. */ return -1; } copy = malloc(data_size); if (copy == NULL) return -1; memcpy(copy, data, data_size); } else copy = NULL; if (q->fd != -1) { size_t offset; offset = entry_offset(q, entry_index); if (full_pwrite(q->fd, data, data_size, offset) != 0) { int saved_errno; saved_errno = errno; if (copy != NULL) free(copy); errno = saved_errno; return -1; } } if (copy != NULL) q->memory[entry_index] = copy; q->queue_length++; return 0; } int q_append(struct queue *q, const char *data) { int r; r = q_append_no_sync_fh_state(q, data); if (r != 0) return r; return sync_fh_state(q); /* Calls q_sync() */ } int q_peek(struct queue *q, char *buf, size_t size) { const unsigned char *data; size_t data_size; if (q->queue_length == 0) return 0; if (q->memory != NULL && q->memory[q->queue_head] != NULL) { data = q->memory[q->queue_head]; data_size = strlen((char *)data) + 1; } else if (q->fd != -1) { const unsigned char *end; if (full_pread(q->fd, q->buffer, q->entry_size, entry_offset(q, q->queue_head)) != 0) return -1; data = q->buffer; end = memchr(q->buffer, '\0', q->entry_size); if (end == NULL) { /* FIXME: silently drop this entry? */ errno = EBADMSG; return -1; } data_size = (end - data) + 1; if (q->memory != NULL) { unsigned char *copy; copy = malloc(data_size); if (copy != NULL) { /* Silently ignore failures. */ memcpy(copy, data, data_size); q->memory[q->queue_head] = copy; } } } else { errno = EIO; /* This is _really_ unexpected. */ return -1; } if (size < data_size) { errno = ERANGE; return -1; } memcpy(buf, data, data_size); return data_size; } /* Internal use only: drop head of Q, but don't write this into the file */ static int q_drop_head_memory_only(struct queue *q) { if (q->queue_length == 0) { errno = EINVAL; return -1; } if (q->memory != NULL) { free(q->memory[q->queue_head]); q->memory[q->queue_head] = NULL; } q->queue_head++; if (q->queue_head == q->num_entries) q->queue_head = 0; q->queue_length--; return 0; } int q_drop_head(struct queue *q) { int r; r = q_drop_head_memory_only(q); if (r != 0) return r; return sync_fh_state(q); /* Calls q_sync() */ } size_t q_queue_length(const struct queue *q) { return q->queue_length; } struct queue *q_open(int q_flags, const char *path, size_t num_entries, size_t entry_size) { struct queue *q, *q2; char *tmp_path, *buf; size_t path_len; int saved_errno, fd; q = q_open_no_resize(q_flags, path, num_entries, entry_size); if (q == NULL || q->num_entries == num_entries) return q; if ((q->flags & Q_RESIZE) == 0) { saved_errno = EINVAL; goto err_errno_q; } if (q->queue_length > num_entries) { saved_errno = ENOSPC; goto err_errno_q; } buf = malloc(entry_size); if (buf == NULL) { saved_errno = errno; goto err_errno_q; } path_len = strlen(path); tmp_path = malloc(path_len + 7); if (tmp_path == NULL) { saved_errno = errno; goto err_errno_buf; } memcpy(tmp_path, path, path_len); memcpy(tmp_path + path_len, "XXXXXX", 7); /* We really want tmpnam() here (safe due to the Q_EXCL below), but gcc warns on any use of tmpnam(). */ fd = mkstemp(tmp_path); if (fd == -1) { saved_errno = errno; goto err_errno_tmp_path; } if (close(fd) != 0 || unlink(tmp_path) != 0) { saved_errno = errno; goto err_errno_tmp_file; } q2 = q_open_no_resize(q_flags | Q_CREAT | Q_EXCL, tmp_path, num_entries, entry_size); if (q2 == NULL) { saved_errno = errno; goto err_errno_tmp_file; } if (q2->num_entries != num_entries) { errno = EIO; /* This is _really_ unexpected. */ goto err_q2; } for (;;) { int r; r = q_peek(q, buf, entry_size); if (r == 0) break; if (r < 0) goto err_q2; if (q_append_no_sync_fh_state(q2, buf) != 0) goto err_q2; if (q_drop_head_memory_only(q) != 0) goto err_q2; } if (sync_fh_state(q2) != 0) goto err_q2; if (rename(tmp_path, path) != 0) goto err_q2; q_close(q); free(buf); free(tmp_path); return q2; err_q2: saved_errno = errno; q_close(q2); err_errno_tmp_file: unlink(tmp_path); err_errno_tmp_path: free(tmp_path); err_errno_buf: free(buf); err_errno_q: q_close(q); errno = saved_errno; return NULL; } audit-userspace-4.0.5/audisp/plugins/remote/queue.h000066400000000000000000000054131501761310600223570ustar00rootroot00000000000000/* queue.h -- a queue abstraction * Copyright 2009, 2011 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Miloslav Trmač */ #ifndef QUEUE_HEADER #define QUEUE_HEADER #include #include "common.h" // attribute decls struct queue; enum { // Queue storage. Both options can be set at the same time. Q_IN_MEMORY = 1 << 0, // Keep a copy of the queue in memory Q_IN_FILE = 1 << 1, // Store the queue in a file // Other flags for use with Q_IN_FILE Q_CREAT = 1 << 2, // Create the queue if it does not exist Q_EXCL = 1 << 3, // With Q_CREAT, don't open an existing queue Q_SYNC = 1 << 4, // fdatasync() after each operation Q_RESIZE = 1 << 5, // resize the queue if needed }; /* MAX_AUDIT_MESSAGE_LENGTH, aligned to 4 KB so that an average q_append() only writes to two disk disk blocks (1 aligned data block, 1 header block). */ #define QUEUE_ENTRY_SIZE (3*4096) /* Close Q. */ void q_close(struct queue *q); /* Open a queue using Q_FLAGS and return it. If Q_IN_FILE: use PATH for the * file, NUM_ENTRIES must be the same for all users of the file unless Q_RESIZE * is set. ENTRY_SIZE is the maximum length of a stored string, including the * trailing NUL. If Q_IN_FILE, it must be the same for all users of the file. * On error, return NULL and set errno. */ struct queue *q_open(int q_flags, const char *path, size_t num_entries, size_t entry_size) __attribute_malloc__ __attr_dealloc (q_close, 1) __wur; /* Add DATA to tail of Q. Return 0 on success, -1 on error and set errno. */ int q_append(struct queue *q, const char *data); /* Peek at head of Q, storing it into BUF of SIZE. Return 1 if an entry * exists, 0 if queue is empty. On error, return -1 and set errno. */ int q_peek(struct queue *q, char *buf, size_t size) __attr_access ((__write_only__, 2, 3)); /* Drop head of Q and return 0. On error, return -1 and set errno. */ int q_drop_head(struct queue *q); /* Return the number of entries in Q. */ size_t q_queue_length(const struct queue *q); #endif audit-userspace-4.0.5/audisp/plugins/remote/remote-config.c000066400000000000000000000473351501761310600237750ustar00rootroot00000000000000/* remote-config.c -- * Copyright 2008,2009,2011,2015-16,2018 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include "remote-config.h" /* Local prototypes */ struct nv_pair { const char *name; const char *value; const char *option; }; struct kw_pair { const char *name; int (*parser)(struct nv_pair *, int, remote_conf_t *); int max_options; }; struct nv_list { const char *name; int option; }; static char *get_line(FILE *f, char *buf); static int nv_split(char *buf, struct nv_pair *nv); static const struct kw_pair *kw_lookup(const char *val); static int server_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int port_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int local_port_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int transport_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int mode_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int queue_file_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int depth_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int format_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int heartbeat_timeout_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int enable_krb5_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int krb5_principal_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int krb5_client_name_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int krb5_key_file_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int network_retry_time_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int max_tries_per_record_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int max_time_per_record_parser(struct nv_pair *nv, int line, remote_conf_t *config); #define AP(x) static int x##_action_parser(struct nv_pair *nv, int line, \ remote_conf_t *config); AP(network_failure) AP(disk_low) AP(disk_full) AP(disk_error) AP(generic_error) AP(generic_warning) AP(queue_error) AP(startup_failure) #undef AP static int remote_ending_action_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int overflow_action_parser(struct nv_pair *nv, int line, remote_conf_t *config); static int sanity_check(remote_conf_t *config, const char *file); static const struct kw_pair keywords[] = { {"remote_server", server_parser, 0 }, {"port", port_parser, 0 }, {"local_port", local_port_parser, 0 }, {"transport", transport_parser, 0 }, {"mode", mode_parser, 0 }, {"queue_file", queue_file_parser, 0 }, {"queue_depth", depth_parser, 0 }, {"format", format_parser, 0 }, {"network_retry_time", network_retry_time_parser, 0 }, {"max_tries_per_record", max_tries_per_record_parser, 0 }, {"max_time_per_record", max_time_per_record_parser, 0 }, {"heartbeat_timeout", heartbeat_timeout_parser, 0 }, {"enable_krb5", enable_krb5_parser, 0 }, {"krb5_principal", krb5_principal_parser, 0 }, {"krb5_client_name", krb5_client_name_parser, 0 }, {"krb5_key_file", krb5_key_file_parser, 0 }, {"network_failure_action", network_failure_action_parser, 1 }, {"disk_low_action", disk_low_action_parser, 1 }, {"disk_full_action", disk_full_action_parser, 1 }, {"disk_error_action", disk_error_action_parser, 1 }, {"remote_ending_action", remote_ending_action_parser, 1 }, {"generic_error_action", generic_error_action_parser, 1 }, {"generic_warning_action", generic_warning_action_parser, 1 }, {"queue_error_action", queue_error_action_parser, 1 }, {"overflow_action", overflow_action_parser, 1 }, {"startup_failure_action", startup_failure_action_parser, 1 }, { NULL, NULL, 0 } }; static const struct nv_list transport_words[] = { {"tcp", T_TCP }, #ifdef USE_GSSAPI {"krb5", T_KRB5 }, #endif { NULL, 0 } }; static const struct nv_list mode_words[] = { {"immediate", M_IMMEDIATE }, {"forward", M_STORE_AND_FORWARD }, { NULL, 0 } }; static const struct nv_list fail_action_words[] = { {"ignore", FA_IGNORE }, {"syslog", FA_SYSLOG }, {"exec", FA_EXEC }, {"warn_once_continue", FA_WARN_ONCE_CONT }, {"warn_once", FA_WARN_ONCE }, {"suspend", FA_SUSPEND }, {"single", FA_SINGLE }, {"halt", FA_HALT }, {"stop", FA_STOP }, { NULL, 0 } }; static const struct nv_list overflow_action_words[] = { {"ignore", OA_IGNORE }, {"syslog", OA_SYSLOG }, {"suspend", OA_SUSPEND }, {"single", OA_SINGLE }, {"halt", OA_HALT }, { NULL, 0 } }; static const struct nv_list format_words[] = { {"ascii", F_ASCII }, {"managed", F_MANAGED }, { NULL, 0 } }; #ifdef USE_GSSAPI static const struct nv_list enable_krb5_values[] = { {"yes", 1 }, {"no", 0 }, { NULL, 0 } }; #endif /* * Set everything to its default value */ void clear_config(remote_conf_t *config) { config->remote_server = NULL; config->port = 60; config->local_port = 0; config->transport = T_TCP; config->mode = M_IMMEDIATE; config->queue_file = NULL; config->queue_depth = 2048; config->format = F_MANAGED; config->network_retry_time = 1; config->max_tries_per_record = 3; config->max_time_per_record = 5; config->heartbeat_timeout = 0; #define IA(x,f) config->x##_action = f; config->x##_exe = NULL IA(network_failure, FA_STOP); IA(disk_low, FA_IGNORE); IA(disk_full, FA_WARN_ONCE); IA(disk_error, FA_WARN_ONCE); IA(remote_ending, FA_RECONNECT); IA(generic_error, FA_SYSLOG); IA(generic_warning, FA_SYSLOG); IA(queue_error, FA_STOP); IA(startup_failure, FA_WARN_ONCE_CONT); #undef IA config->overflow_action = OA_SYSLOG; config->krb5_principal = NULL; config->krb5_client_name = NULL; config->krb5_key_file = NULL; } int load_config(remote_conf_t *config, const char *file) { int fd, rc, mode, lineno = 1; struct stat st; FILE *f; char buf[128]; clear_config(config); /* open the file */ mode = O_RDONLY; rc = open(file, mode); if (rc < 0) { if (errno != ENOENT) { syslog(LOG_ERR, "Error opening %s (%s)", file, strerror(errno)); return 1; } syslog(LOG_WARNING, "Config file %s doesn't exist, skipping", file); return 0; } fd = rc; /* check the file's permissions: owned by root, not world writable, * not symlink. */ if (fstat(fd, &st) < 0) { syslog(LOG_ERR, "Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { syslog(LOG_ERR, "Error - %s isn't owned by root", file); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { syslog(LOG_ERR, "Error - %s is world writable", file); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { syslog(LOG_ERR, "Error - %s is not a regular file", file); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { syslog(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf)) { // convert line into name-value pair const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. syslog(LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, file); break; case 2: // no '=' sign syslog(LOG_ERR, "Missing equal sign for line %d in %s", lineno, file); break; default: // something else went wrong... syslog(LOG_ERR, "Unknown error for line %d in %s", lineno, file); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { syslog(LOG_ERR, "Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, file); fclose(f); return 1; } /* Check number of options */ if (kw->max_options == 0 && nv.option != NULL) { syslog(LOG_ERR, "Keyword \"%s\" has invalid option " "\"%s\" in line %d of %s", nv.name, nv.option, lineno, file); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(&nv, lineno, config); if (rc != 0) { fclose(f); return 1; // local parser puts message out } lineno++; } fclose(f); if (lineno > 1) return sanity_check(config, file); return 0; } static char *get_line(FILE *f, char *buf) { if (fgets_unlocked(buf, 128, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) *ptr = 0; return buf; } return NULL; } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr, *saved; nv->name = NULL; nv->value = NULL; nv->option = NULL; ptr = strtok_r(buf, " ", &saved); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = strtok_r(NULL, " ", &saved); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = strtok_r(NULL, " ", &saved); if (ptr == NULL) return 1; nv->value = ptr; /* See if there's an option */ ptr = strtok_r(NULL, " ", &saved); if (ptr) { nv->option = ptr; /* Make sure there's nothing else */ ptr = strtok_r(NULL, " ", &saved); if (ptr) return 1; } /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int check_exe_name(const char *val, int line) { struct stat buf; if (val == NULL) { syslog(LOG_ERR, "Executable path needed for line %d", line); return -1; } if (*val != '/') { syslog(LOG_ERR, "Absolute path needed for %s - line %d", val, line); return -1; } if (stat(val, &buf) < 0) { syslog(LOG_ERR, "Unable to stat %s (%s) - line %d", val, strerror(errno), line); return -1; } if (!S_ISREG(buf.st_mode)) { syslog(LOG_ERR, "%s is not a regular file - line %d", val, line); return -1; } if (buf.st_uid != 0) { syslog(LOG_ERR, "%s is not owned by root - line %d", val, line); return -1; } if ((buf.st_mode & (S_IRWXU|S_IRWXG|S_IWOTH)) != (S_IRWXU|S_IRGRP|S_IXGRP)) { syslog(LOG_ERR, "%s permissions should be 0750 - line %d", val, line); return -1; } return 0; } static int server_parser(struct nv_pair *nv, int line, remote_conf_t *config) { if (nv->value) config->remote_server = strdup(nv->value); else config->remote_server = NULL; return 0; } static int parse_uint (const struct nv_pair *nv, int line, unsigned int *valp, unsigned int min, unsigned int max) { const char *ptr = nv->value; unsigned int i; /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { syslog(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { syslog(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (min != 0 && i < (int)min) { syslog(LOG_ERR, "Error - converted number (%s) is too small - line %d", nv->value, line); return 1; } if (max != 0 && i > max) { syslog(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } *valp = (unsigned int)i; return 0; } static int port_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint (nv, line, &(config->port), 0, 65535); } static int local_port_parser(struct nv_pair *nv, int line, remote_conf_t *config) { if ((strcasecmp(nv->value, "any") == 0)) return 0; // The default is 0, which means any port return parse_uint (nv, line, &(config->local_port), 0, 65535); } static int transport_parser(struct nv_pair *nv, int line, remote_conf_t *config) { int i; for (i=0; transport_words[i].name != NULL; i++) { if (strcasecmp(nv->value, transport_words[i].name) == 0) { config->transport = transport_words[i].option; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int mode_parser(struct nv_pair *nv, int line, remote_conf_t *config) { int i; for (i=0; mode_words[i].name != NULL; i++) { if (strcasecmp(nv->value, mode_words[i].name) == 0) { config->mode = mode_words[i].option; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int queue_file_parser(struct nv_pair *nv, int line, remote_conf_t *config) { if (nv->value) { if (*nv->value != '/') { syslog(LOG_ERR, "Absolute path needed for %s - line %d", nv->value, line); return 1; } config->queue_file = strdup(nv->value); } else config->queue_file = NULL; return 0; } static int depth_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint (nv, line, &(config->queue_depth), 1, INT_MAX); } static int action_parser(struct nv_pair *nv, int line, failure_action_t *actp, const char **exep) { int i; for (i=0; fail_action_words[i].name != NULL; i++) { if (strcasecmp(nv->value, fail_action_words[i].name) == 0) { if (fail_action_words[i].option == FA_EXEC) { if (check_exe_name(nv->option, line)) return 1; *exep = strdup(nv->option); } *actp = fail_action_words[i].option; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } #define AP(x) \ static int x##_action_parser(struct nv_pair *nv, int line, \ remote_conf_t *config) \ { \ return action_parser(nv,line,&(config->x##_action),&(config->x##_exe));\ } \ AP(network_failure) AP(disk_low) AP(disk_full) AP(disk_error) AP(generic_error) AP(generic_warning) AP(queue_error) AP(startup_failure) #undef AP static int overflow_action_parser(struct nv_pair *nv, int line, remote_conf_t *config) { int i; for (i=0; overflow_action_words[i].name != NULL; i++) { if (strcasecmp(nv->value, overflow_action_words[i].name) == 0) { config->overflow_action = overflow_action_words[i].option; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int remote_ending_action_parser(struct nv_pair *nv, int line, remote_conf_t *config) { if (strcasecmp(nv->value, "reconnect") == 0) { config->remote_ending_action = FA_RECONNECT; return 0; } return action_parser(nv, line, &config->remote_ending_action, &config->remote_ending_exe); } static int format_parser(struct nv_pair *nv, int line, remote_conf_t *config) { int i; for (i=0; format_words[i].name != NULL; i++) { if (strcasecmp(nv->value, format_words[i].name) == 0) { config->format = format_words[i].option; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int network_retry_time_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint(nv, line, &config->network_retry_time, 1, INT_MAX); } static int max_tries_per_record_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint(nv, line, &config->max_tries_per_record, 1, INT_MAX); } static int max_time_per_record_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint(nv, line, &(config->max_time_per_record), 1, INT_MAX); } static int heartbeat_timeout_parser(struct nv_pair *nv, int line, remote_conf_t *config) { return parse_uint (nv, line, &(config->heartbeat_timeout), 0, INT_MAX); } static int enable_krb5_parser(struct nv_pair *nv, int line, remote_conf_t *config) { #ifndef USE_GSSAPI syslog(LOG_INFO, "GSSAPI support is not enabled, ignoring value at line %d", line); return 0; #else unsigned long i; for (i=0; enable_krb5_values[i].name != NULL; i++) { if (strcasecmp(nv->value, enable_krb5_values[i].name) == 0) { if (enable_krb5_values[i].option == 1) config->transport = T_KRB5; return 0; } } syslog(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; #endif } static int krb5_principal_parser(struct nv_pair *nv, int line, remote_conf_t *config) { #ifndef USE_GSSAPI syslog(LOG_INFO, "GSSAPI support is not enabled, ignoring value at line %d", line); #else if (config->krb5_principal) free ((char *)config->krb5_principal); config->krb5_principal = strdup(nv->value); #endif return 0; } static int krb5_client_name_parser(struct nv_pair *nv, int line, remote_conf_t *config) { #ifndef USE_GSSAPI syslog(LOG_INFO, "GSSAPI support is not enabled, ignoring value at line %d", line); #else if (config->krb5_client_name) free ((char *)config->krb5_client_name); config->krb5_client_name = strdup(nv->value); #endif return 0; } static int krb5_key_file_parser(struct nv_pair *nv, int line, remote_conf_t *config) { #ifndef USE_GSSAPI syslog(LOG_INFO, "GSSAPI support is not enabled, ignoring value at line %d", line); #else if (config->krb5_key_file) free ((char *)config->krb5_key_file); config->krb5_key_file = strdup(nv->value); #endif return 0; } /* * This function is where we do the integrated check of the config * options. At this point, all fields have been read. Returns 0 if no * problems and 1 if problems detected. */ static int sanity_check(remote_conf_t *config, const char *file) { /* Error checking */ // server should have string // port should be less that 32k // queue_depth should be less than 100k // If fail_action is F_EXEC, fail_exec must exist if (config->mode == M_STORE_AND_FORWARD && config->format != F_MANAGED) { syslog(LOG_ERR, "\"mode=forward\" is valid only with " "\"format=managed\""); return 1; } if (config->startup_failure_action > FA_EXEC) { syslog(LOG_ERR, "startup_failure_action has invalid option"); return 1; } return 0; } void free_config(remote_conf_t *config) { free((void *)config->remote_server); free((void *)config->queue_file); free((void *)config->network_failure_exe); free((void *)config->disk_low_exe); free((void *)config->disk_full_exe); free((void *)config->disk_error_exe); free((void *)config->remote_ending_exe); free((void *)config->generic_error_exe); free((void *)config->generic_warning_exe); free((void *)config->queue_error_exe); free((void *)config->startup_failure_exe); free((void *)config->krb5_principal); free((void *)config->krb5_client_name); free((void *)config->krb5_key_file); } audit-userspace-4.0.5/audisp/plugins/remote/remote-config.h000066400000000000000000000051441501761310600237720ustar00rootroot00000000000000/* remote-config.h -- * Copyright 2008,2009,2011,2016,2018 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef REMOTE_CONFIG_H #define REMOTE_CONFIG_H typedef enum { M_IMMEDIATE, M_STORE_AND_FORWARD } rmode_t; typedef enum { T_TCP, T_TLS, T_KRB5, T_LABELED } transport_t; typedef enum { F_ASCII, F_MANAGED } format_t; typedef enum { FA_IGNORE, FA_SYSLOG, FA_WARN_ONCE_CONT, FA_WARN_ONCE, FA_EXEC, FA_RECONNECT, FA_SUSPEND, FA_SINGLE, FA_HALT, FA_STOP } failure_action_t; typedef enum { OA_IGNORE, OA_SYSLOG, OA_SUSPEND, OA_SINGLE, OA_HALT } overflow_action_t; typedef struct remote_conf { const char *remote_server; unsigned int port; unsigned int local_port; transport_t transport; rmode_t mode; const char *queue_file; unsigned int queue_depth; format_t format; unsigned int network_retry_time; unsigned int max_tries_per_record; unsigned int max_time_per_record; unsigned int heartbeat_timeout; const char *krb5_principal; const char *krb5_client_name; const char *krb5_key_file; failure_action_t network_failure_action; const char *network_failure_exe; failure_action_t disk_low_action; const char *disk_low_exe; failure_action_t disk_full_action; const char *disk_full_exe; failure_action_t disk_error_action; const char *disk_error_exe; failure_action_t remote_ending_action; const char *remote_ending_exe; failure_action_t generic_error_action; const char *generic_error_exe; failure_action_t generic_warning_action; const char *generic_warning_exe; failure_action_t queue_error_action; const char *queue_error_exe; overflow_action_t overflow_action; const char *startup_failure_exe; failure_action_t startup_failure_action; } remote_conf_t; void clear_config(remote_conf_t *config); int load_config(remote_conf_t *config, const char *file); void free_config(remote_conf_t *config); #endif audit-userspace-4.0.5/audisp/plugins/remote/test-queue.c000066400000000000000000000176701501761310600233370ustar00rootroot00000000000000/* test-queue.c -- test suite for persistent-queue.c * Copyright 2011,2018 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include #include #include "queue.h" #define NUM_ENTRIES 7 /* 3*4096, larger than MAX_AUDIT_MESSAGE_LENGTH. The same value is used in the main audisp-remote code. */ #define ENTRY_SIZE 12288 static char filename[] = "/tmp/tqXXXXXX"; static struct queue *q; static char *sample_entries[NUM_ENTRIES - 1]; #define NUM_SAMPLE_ENTRIES (sizeof(sample_entries) / sizeof(*sample_entries)) #define die(...) die__(__LINE__, __VA_ARGS__) static void __attribute__((format (printf, 2, 3))) die__(int line, const char *message, ...) { va_list ap; fprintf(stderr, "test-queue: %d: ", line); va_start(ap, message); vfprintf(stderr, message, ap); va_end(ap); putc('\n', stderr); abort(); } #define err(...) err__(__LINE__, __VA_ARGS__) static void __attribute__((format (printf, 2, 3))) err__(int line, const char *message, ...) { char *errno_str; va_list ap; errno_str = strerror(errno); fprintf(stderr, "test-queue: %d: ", line); va_start(ap, message); vfprintf(stderr, message, ap); va_end(ap); fprintf(stderr, ": (%d) %s\n", errno, errno_str); abort(); } static void init_sample_entries(void) { size_t i; for (i = 0; i < NUM_SAMPLE_ENTRIES; i++) { char *e; size_t j, len; len = rand() % ENTRY_SIZE; e = malloc(len + 1); if (e == NULL) err("malloc"); for (j = 0; j < len; j++) e[j] = rand() % CHAR_MAX + 1; e[j] = '\0'; sample_entries[i] = e; } } static void free_sample_entries(void) { size_t i; for (i = 0; i < NUM_SAMPLE_ENTRIES; i++) free(sample_entries[i]); } static void test_q_open(void) { struct queue *q2; /* Test that flags are honored */ q2 = q_open(Q_IN_FILE | Q_CREAT | Q_EXCL, filename, NUM_ENTRIES, ENTRY_SIZE); if (q2 != NULL) die("q_open didn't fail"); if (errno != EEXIST) err("q_open"); /* Test that locking is enforced. Use a separate process because fcntl()/lockf() locking is attached to processes, not file descriptors. */ fflush(NULL); switch (fork()) { case -1: err("fork"); case 0: q2 = q_open(Q_IN_FILE, filename, NUM_ENTRIES, ENTRY_SIZE); if (q2 != NULL) die("q_open didn't fail"); if (errno != EBUSY) err("q_open"); _exit(0); default: { int status; if (wait(&status) == (pid_t)-1) err("wait"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) die("wait status %d", status); } } } static void test_empty_q (void) { char buf[ENTRY_SIZE]; if (q_peek(q, buf, sizeof(buf)) != 0) die("q_peek reports non-empty"); if (q_drop_head(q) != -1) die("q_drop_head didn't fail"); if (errno != EINVAL) err("q_drop_head"); if (q_queue_length(q) != 0) die("Unexpected q_queue_length"); } static void test_basic_data (void) { char buf[ENTRY_SIZE + 1]; int i; if (q_append(q, " ") != 0) die("q_append"); memset (buf, 'A', ENTRY_SIZE); buf[ENTRY_SIZE] = '\0'; if (q_append(q, buf) != -1) die("q_append didn't fail"); if (errno != EINVAL) err("q_append"); buf[ENTRY_SIZE - 1] = '\0'; if (q_append(q, buf) != 0) die("q_append"); if (q_queue_length(q) != 2) die("Unexpected q_queue_length"); if (q_peek(q, buf, sizeof(buf)) < 1) err("q_peek"); if (strcmp(buf, " ") != 0) die("invalid data returned"); if (q_drop_head(q) != 0) err("q_drop_head"); if (q_peek(q, buf, ENTRY_SIZE - 1) != -1) err("q_peek didn't fail"); if (errno != ERANGE) err("q_peek"); for (i = 0; i < 2; i++) { size_t j; if (q_peek(q, buf, sizeof(buf)) < 1) err("q_peek"); for (j = 0; j < ENTRY_SIZE - 1; j++) { if (buf[j] != 'A') die("invalid data at %zu", j); } if (buf[j] != '\0') die("invalid data at %zu", j); } if (q_drop_head(q) != 0) err("q_drop_head"); if (q_queue_length(q) != 0) die("Unexpected q_queue_length"); } static void append_sample_entries(size_t count) { size_t i; for (i = 0; i < count; i++) { if (q_append(q, sample_entries[i % NUM_SAMPLE_ENTRIES]) != 0) die("q_append %zu", i); } } static void verify_sample_entries(size_t count) { char buf[ENTRY_SIZE + 1]; size_t i; if (q_queue_length(q) != count) die("Unexpected q_queue_length"); for (i = 0; i < count; i++) { if (q_peek(q, buf, sizeof(buf)) < 1) err("q_peek %zu", i); if (strcmp(buf, sample_entries[i % NUM_SAMPLE_ENTRIES]) != 0) die("invalid data %zu", i); if (q_drop_head(q) != 0) err("q_drop_head"); } if (q_peek(q, buf, sizeof(buf)) != 0) die("q_peek reports non-empty"); } static void test_run(int flags) { size_t j; q = q_open(flags | Q_CREAT | Q_EXCL, filename, NUM_ENTRIES, ENTRY_SIZE); if (q == NULL) err("q_open"); if ((flags & Q_IN_FILE) != 0) test_q_open(); /* Do this enough times to get a wraparound */ for (j = 0; j < NUM_ENTRIES; j++) { test_empty_q(); test_basic_data(); } append_sample_entries(NUM_ENTRIES - 1); if (q_queue_length(q) != NUM_ENTRIES - 1) die("Unexpected q_queue_length"); q_close(q); q = q_open(flags, filename, NUM_ENTRIES, ENTRY_SIZE); if (q == NULL) err("q_open"); if ((flags & Q_IN_FILE) != 0) /* Test that the queue can be reopened and data has been preserved. */ verify_sample_entries(NUM_ENTRIES - 1); else /* Test that a new in-memory queue is empty. */ verify_sample_entries(0); q_close(q); if ((flags & Q_IN_FILE) != 0 && unlink(filename) != 0) err("unlink"); } static void test_resizing(void) { q = q_open(Q_IN_FILE | Q_CREAT | Q_EXCL, filename, NUM_ENTRIES, ENTRY_SIZE); if (q == NULL) err("q_open"); append_sample_entries(NUM_ENTRIES); if (q_queue_length(q) != NUM_ENTRIES) die("Unexpected q_queue_length"); q_close(q); /* Verify num_entries is validated */ q = q_open(Q_IN_FILE, filename, NUM_ENTRIES + 1, ENTRY_SIZE); if (q != NULL) die("q_open didn't fail"); if (errno != EINVAL) err("q_open"); q = q_open(Q_IN_FILE, filename, NUM_ENTRIES - 1, ENTRY_SIZE); if (q != NULL) die("q_open didn't fail"); if (errno != EINVAL) err("q_open"); /* Test increasing size */ q = q_open(Q_IN_FILE | Q_RESIZE, filename, 2 * NUM_ENTRIES, ENTRY_SIZE); if (q == NULL) err("q_open"); verify_sample_entries(NUM_ENTRIES); append_sample_entries(NUM_ENTRIES); q_close(q); /* Test decreasing size */ q = q_open(Q_IN_FILE | Q_RESIZE, filename, NUM_ENTRIES / 2, ENTRY_SIZE); if (q != NULL) die("q_open didn't fail"); if (errno != ENOSPC) err("q_open"); q = q_open(Q_IN_FILE | Q_RESIZE, filename, NUM_ENTRIES, ENTRY_SIZE); if (q == NULL) err("q_open"); verify_sample_entries(NUM_ENTRIES); q_close(q); if (unlink(filename) != 0) err("unlink"); } int main(void) { static const int flags[] = { Q_IN_MEMORY, Q_IN_FILE, Q_IN_FILE | Q_SYNC, Q_IN_MEMORY | Q_IN_FILE }; int fd; size_t i; init_sample_entries(); /* We really want tmpnam() here (safe due to the Q_EXCL below), but gcc warns on any use of tmpnam(). */ fd = mkstemp(filename); if (fd == -1) err("tmpnam"); if (close(fd) != 0) err("close"); if (unlink(filename) != 0) err("unlink"); for (i = 0; i < sizeof(flags) / sizeof(*flags); i++) test_run(flags[i]); test_resizing(); free_sample_entries(); return EXIT_SUCCESS; } audit-userspace-4.0.5/audisp/plugins/statsd/000077500000000000000000000000001501761310600210665ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/statsd/Makefile.am000066400000000000000000000036021501761310600231230ustar00rootroot00000000000000# Makefile.am -- # Copyright 2021 Steve Grubb. # All Rights Reserved. # # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = au-statsd.conf audisp-statsd.conf $(man_MANS) AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse -I${top_srcdir}/common prog_confdir = $(sysconfdir)/audit prog_conf = audisp-statsd.conf plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = au-statsd.conf sbin_PROGRAMS = audisp-statsd man_MANS = audisp-statsd.8 audisp_statsd_SOURCES = audisp-statsd.c audisp_statsd_CFLAGS = -g -D_GNU_SOURCE ${WFLAGS} audisp_statsd_LDADD = $(CAPNG_LDADD) ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la audisp_statsd_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(prog_conf) ${DESTDIR}${prog_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) rm ${DESTDIR}${prog_confdir}/$(prog_conf) audit-userspace-4.0.5/audisp/plugins/statsd/au-statsd.conf000066400000000000000000000003171501761310600236430ustar00rootroot00000000000000# This file controls the configuration of the statsd plugin. # It picks out metrics and writes them to statsd. active = no direction = out path = /sbin/audisp-statsd type = always # args = format = string audit-userspace-4.0.5/audisp/plugins/statsd/audisp-statsd.8000066400000000000000000000046461501761310600237560ustar00rootroot00000000000000.TH AUDISP-STATSD "8" "June 2025" "Red Hat" "System Administration Utilities" .SH NAME audisp-statsd \- plugin to push audit metrics to a statsd service .SH SYNOPSIS .B audisp-statsd [ \fIOPTIONS\fP ] .SH DESCRIPTION \fBaudisp-statsd\fP is a plugin for the audit event dispatcher that pushes audit metrics to a statsd service using UDP. It reads auditd's state report at regular intervals and forwards the data. Generation of the state report must be enabled in \fBauditd.conf\fP. .SH CONFIGURATION The plugin's configuration file is \fB/etc/audit/audisp-statsd.conf\fP. The following parameters are recognized: .TP .I address The name or address of the statsd server. .TP .I port The UDP port of the statsd service. .TP .I interval Time interval between reading auditd's report. The value is a time string such as 10m, 1h, 2d, or 6M where the suffix is s for seconds, m for minutes, h for hours, d for days, and M for months. The default is 15s. .SH REPORT METRICS The plugin collects the following metrics as gauges: .RS .TP .B backlog number of kernel events pending transfer to user space .TP .B lost number of kernel events dropped .TP .B free_space how much disk free space auditd sees in MB .TP .B plugin_current_depth number of events in auditd pending transfer to plugins .TP .B plugin_max_depth historical maximum number of events backlogged while pending transfer to plugins .TP .B total_memory current total memory in use by glibc in KB .TP .B memory_in_use how much of the total memory is actively used in KB .TP .B memory_free amount of free memory available in the glibc arenas in KB .RE The following metrics are counters: .RS .TP .B events_total_count total number of events seen during interval .TP .B events_total_failed total number of events seen during interval with failed outcome .TP .B events_avc_count total number of AVC events seen during interval .TP .B events_fanotify_count total number of FANOTIFY events seen during interval .TP .B events_logins_success total number of successful login events seen during interval .TP .B events_logins_failed total number of failed login events seen during interval .TP .B events_anamoly_count total number of anamoly events seen during interval .TP .B events_response_count total number of anamoly response events seen during interval .RE .SH FILES /etc/audit/audisp-statsd.conf /etc/audit/plugins/au-statsd.conf .SH "SEE ALSO" .BR auditd.conf (8), .BR auditd-plugins (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/audisp/plugins/statsd/audisp-statsd.c000066400000000000000000000311271501761310600240230ustar00rootroot00000000000000/* audisp-statsd.c -- * Copyright 2021 Steve Grubb * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCAP_NG #include #endif #include "libaudit.h" #include "auparse.h" #include "common.h" /* Global Definitions */ #define STATE_REPORT "/var/run/auditd.state" #define CONFIG "/etc/audit/audisp-statsd.conf" struct daemon_config { char address[65]; unsigned int port; unsigned int interval; int sock; struct sockaddr_storage addr; socklen_t addrlen; }; struct audit_report { unsigned int backlog; unsigned int lost; long long unsigned int free_space; unsigned int plugin_current_depth; unsigned int plugin_max_depth; unsigned long long total_memory; unsigned long long memory_in_use; unsigned long long memory_free; unsigned int events_total_count; unsigned int events_total_failed; unsigned int events_avc_count; unsigned int events_fanotify_count; unsigned int events_logins_success; unsigned int events_logins_failed; unsigned int events_anomaly_count; unsigned int events_response_count; }; /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static int audit_fd = -1; static auparse_state_t *au = NULL; static int timer_fd = -1; static char msg[MAX_AUDIT_MESSAGE_LENGTH + 1]; static struct daemon_config d; static struct audit_report r; /* Local function prototypes */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); /* * SIGTERM handler: exit time */ static void term_handler(int sig) { stop = sig; } /* * SIGHUP handler: re-read config */ static void hup_handler(int sig) { hup = sig; } /* * Get the next config file line and clean it up a little */ static char *get_line(FILE *f, char *buf, size_t len) { if (fgets(buf, len, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) *ptr = 0; return buf; } return NULL; } /* * Load the plugin's configuration. Returns 1 on failure and 0 on success. */ static int load_config(void) { unsigned int status = 0; int line = 0; char buf[128]; FILE *f = fopen(CONFIG, "rt"); if (f == NULL) { fprintf(stderr, "Cannot open config file\n"); return 1; } while (get_line(f, buf, sizeof(buf))) { line++; switch (buf[0]) { case 'a': sscanf(buf, "address = %64s", d.address); status |= 0x01; break; case 'p': sscanf(buf, "port = %u", &d.port); status |= 0x02; break; case 'i': { char tstr[64]; long t; if (sscanf(buf, "interval = %63s", tstr) != 1) { fprintf(stderr, "bad interval format\n"); fclose(f); return 1; } t = time_string_to_seconds(tstr, "statsd", line); if (t < 0) { fclose(f); return 1; } d.interval = (unsigned int)t; status |= 0x04; break; } case 0: case '#': // Comments break; default: fprintf(stderr, "unknown option\n"); fclose(f); return 1; } } fclose(f); if (status != 0x07) { fprintf(stderr, "Not all config options specified\n"); return 1; } return 0; } /* * Given the configuration data, turn it into a usable address for use * with sendto later. */ int make_socket(void) { int rc; struct addrinfo hints, *ai; char port[16]; // Resolve the remote host memset(&hints, '\0', sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV; hints.ai_socktype = SOCK_DGRAM; snprintf(port, sizeof(port), "%u", d.port); rc = getaddrinfo(d.address, port, &hints, &ai); if (rc) { syslog(LOG_ERR, "error looking up statsd service\n"); return -1; } d.sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); memcpy(&d.addr, ai->ai_addr, ai->ai_addrlen); d.addrlen = ai->ai_addrlen; freeaddrinfo(ai); return d.sock; } /* * Reset all the report parameters */ static void clear_report(void) { r.lost = 0; r.backlog = 0; r.free_space = 0; r.plugin_current_depth = 0; r.plugin_max_depth = 0; r.total_memory = 0; r.memory_in_use = 0; r.memory_free = 0; r.events_total_count = 0; r.events_total_failed = 0; r.events_avc_count = 0; r.events_fanotify_count = 0; r.events_logins_success = 0; r.events_logins_failed = 0; r.events_anomaly_count = 0; r.events_response_count = 0; } /* * Pull the current status from the kernel */ static void get_kernel_status(void) { struct audit_reply rep; audit_request_status(audit_fd); int rc = audit_get_reply(audit_fd, &rep, GET_REPLY_BLOCKING, 0); if (rc > 0 && rep.type == AUDIT_GET) { // add info to global audit event struct r.lost = rep.status->lost; r.backlog = rep.status->backlog; } } /* * Collect free_space, plugin_current_depth, and plugin_max_depth * out of the auditd state report. */ static void get_auditd_status(void) { // auditd generates the state report periodically on its own FILE *f = fopen(STATE_REPORT, "rt"); if (f) { char buf[80]; __fsetlocking(f, FSETLOCKING_BYCALLER); while (fgets(buf, sizeof(buf), f)) { if (memcmp(buf, "Logging", 7) == 0) { sscanf(buf, "Logging partition free space = %llu", &r.free_space); } else if (memcmp(buf, "current plugin", 14) == 0) { sscanf(buf, "current plugin queue depth = %u", &r.plugin_current_depth); } else if (memcmp(buf, "max plugin", 10) == 0) { sscanf(buf, "max plugin queue depth used = %u", &r.plugin_max_depth); } else if (memcmp(buf, "glibc arena", 11) == 0) { sscanf(buf, "glibc total memory is: %llu", &r.total_memory); } else if (memcmp(buf, "glibc uordblks", 13) == 0) { sscanf(buf, "glibc in use memory is: %llu", &r.memory_in_use); } else if (memcmp(buf, "glibc fordblks", 14) == 0) { sscanf(buf, "glibc total free space is: %llu", &r.memory_free); break; // This is last item, break free } } fclose(f); } } /* * Format and send the report metrics to the statsd service. */ static void send_statsd(void) { // The message size has to stay under the MTU for the network // 512 should be low enough to survive the commodity internet char message[512]; int len; // grab the global audit event struct and format it // format - :| // Things pulled from kernel or auditd are gauges. Anything // incremented (events) are counters. len = snprintf(message, sizeof(message), "kernel.lost:%u|g\nkernel.backlog:%u|g\n" "auditd.free_space:%llu|g\nauditd.plugin_current_depth:%u|g\nauditd.plugin_max_depth:%u|g\n" "auditd.total_memory:%llu|g\nauditd.memory_in_use:%llu|g\nauditd.memory_free:%llu|g\n" "events.total_count:%u|c\nevents.total_failed:%u|c\n" "events.avc_count:%u|c\nevents.fanotify_count:%u|c\n" "events.logins_success:%u|c\nevents.logins_failed:%u|c\n" "events.anomaly_count:%u|c\nevents.response_count:%u|c\n", r.lost, r.backlog, r.free_space, r.plugin_current_depth, r.plugin_max_depth, r.total_memory, r.memory_in_use, r.memory_free, r.events_total_count, r.events_total_failed, r.events_avc_count, r.events_fanotify_count, r.events_logins_success, r.events_logins_failed, r.events_anomaly_count, r.events_response_count); if (len > 0 && len < (int)sizeof(message)) sendto(d.sock, message, len, 0, (struct sockaddr *)&d.addr, d.addrlen); } int main(void) { struct sigaction sa; struct pollfd pfd[2]; struct itimerspec itval; int rc; if (geteuid() != 0) { fprintf(stderr, "You need to be root to run this\n"); return 1; } if (load_config()) { syslog(LOG_ERR, "Failed loading config - exiting"); return 1; } // Setup signal handlers sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); // Create the socket d.sock = make_socket(); if (d.sock < 0) { syslog(LOG_ERR, "Failed creating socket - exiting"); return 1; } #ifdef HAVE_LIBCAP_NG // Drop capabilities - audit control required for AUDIT_GET capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED, CAP_AUDIT_CONTROL); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "audisp-statsd failed dropping capabilities, continuing with elevated priviliges"); #endif // Initialize auparse clear_report(); au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { close(d.sock); syslog(LOG_ERR, "exiting due to auparse init errors"); return 1; } auparse_set_eoe_timeout(5); auparse_add_callback(au, handle_event, NULL, NULL); audit_fd = audit_open(); if (audit_fd < 0) { close(d.sock); syslog(LOG_ERR, "unable to open audit socket"); return 1; } fcntl(0, F_SETFL, O_NONBLOCK); /* Set STDIN non-blocking */ pfd[0].fd = 0; // add stdin to the poll group pfd[0].events = POLLIN; // Initialize interval timer timer_fd = timerfd_create (CLOCK_MONOTONIC, 0); if (timer_fd < 0) { syslog(LOG_ERR, "unable to open a timerfd"); return 1; } pfd[1].fd = timer_fd; pfd[1].events = POLLIN; itval.it_interval.tv_sec = d.interval; itval.it_interval.tv_nsec = 0; itval.it_value.tv_sec = itval.it_interval.tv_sec; itval.it_value.tv_nsec = 0; timerfd_settime(timer_fd, 0, &itval, NULL); // Start event loop while (!stop) { rc = poll(pfd, 2, -1); if (rc < 0) { if (errno == EINTR) continue; } else if (rc > 0) { // timer if (pfd[1].revents & POLLIN) { unsigned long long missed; missed=read(timer_fd, &missed, sizeof (missed)); // Clear any old events if possible if (auparse_feed_has_data(au)) auparse_feed_age_events(au); get_kernel_status(); get_auditd_status(); send_statsd(); clear_report(); } // audit event if (pfd[0].revents & POLLIN) { int len; while ((len = read(0, msg, MAX_AUDIT_MESSAGE_LENGTH)) > 0) { msg[len] = 0; auparse_feed(au, msg, len); } } } } // tear down everything close(timer_fd); auparse_destroy(au); close(audit_fd); close(d.sock); if (stop) syslog(LOG_INFO, "audisp-statsd is exiting on stop request"); else syslog(LOG_INFO, "audisp-statsd is exiting"); return 0; } /* * Given a completed event, parse it up and increment various counters * based on what we see. */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data __attribute__((unused))) { int type; const char *success; if (cb_event_type != AUPARSE_CB_EVENT_READY) return; // Need to put everything in the global struct // r.events_total_count; // r.events_total_failed; // r.events_avc_count; // r.events_fanotify_count; // r.events_logins_success; // r.events_logins_failed; // r.events_anomaly_count; // r.events_response_count r.events_total_count++; auparse_normalize(au, NORM_OPT_NO_ATTRS); auparse_normalize_get_results(au); success = auparse_interpret_field(au); if (success && strcmp(success, "no") == 0) r.events_total_failed++; auparse_first_record(au); type = auparse_get_type(au); switch (type) { // These take advantage of knowing that this is the first // record in the whole event. If this ever changes then all // bets are off. case AUDIT_USER_LOGIN: if (success) { if (strcmp(success, "no") == 0) r.events_logins_failed++; else r.events_logins_success++; } break; case AUDIT_FANOTIFY: r.events_fanotify_count++; break; case AUDIT_AVC: r.events_avc_count++; break; case AUDIT_FIRST_ANOM_MSG...AUDIT_LAST_ANOM_MSG: r.events_anomaly_count++; break; case AUDIT_FIRST_ANOM_RESP...AUDIT_LAST_ANOM_RESP: r.events_response_count++; break; } } audit-userspace-4.0.5/audisp/plugins/statsd/audisp-statsd.conf000066400000000000000000000005061501761310600245230ustar00rootroot00000000000000# This file points audisp-statsd to the statsd server. The interval is # the time between reading auditd's state report. The interval may be a # time string such as 10m, 1h, 2d, or 6M where the suffix is s for # seconds, m for minutes, h for hours, d for days, and M for months. address = localhost port = 8125 interval = 15s audit-userspace-4.0.5/audisp/plugins/syslog/000077500000000000000000000000001501761310600211045ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/syslog/Makefile.am000066400000000000000000000034571501761310600231510ustar00rootroot00000000000000# Makefile.am -- # Copyright 2018,19 Red Hat Inc. # All Rights Reserved. # # 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 General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = syslog.conf $(man_MANS) # FIXME: remove common AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/common -I${top_srcdir}/auparse -I${top_srcdir}/common prog_confdir = $(sysconfdir)/audit plugin_confdir=$(prog_confdir)/plugins.d plugin_conf = syslog.conf sbin_PROGRAMS = audisp-syslog man_MANS = audisp-syslog.8 audisp_syslog_DEPENDENCIES = ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la audisp_syslog_SOURCES = audisp-syslog.c audisp_syslog_CFLAGS = -fPIE -DPIE -g -D_GNU_SOURCE -Wundef ${WFLAGS} audisp_syslog_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now audisp_syslog_LDADD = $(CAPNG_LDADD) ${top_builddir}/auparse/libauparse.la ${top_builddir}/auparse/libauparse.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) ${DESTDIR}${plugin_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) audit-userspace-4.0.5/audisp/plugins/syslog/audisp-syslog.8000066400000000000000000000027231501761310600240040ustar00rootroot00000000000000.TH AUDISP-SYSLOG "8" "August 2018" "Red Hat" "System Administration Utilities" .SH NAME audisp-syslog \- plugin to push audit events into syslog .SH SYNOPSIS .B audisp-syslog [ \fIOPTIONS\fP ] .SH DESCRIPTION \fBaudisp-syslog\fP is a plugin for the audit event dispatcher that wraps audit events back around to syslog. It can be passed three options: one which is the syslog facility, one that is the syslog level that all events are logged with, and one that determines if events should be interpreted. Valid facilities are LOG_LOCAL0 through 7, LOG_AUTH, LOG_AUTHPRIV, LOG_DAEMON, LOG_SYSLOG, and LOG_USER. Valid levels are LOG_DEBUG through LOG_EMERG. Setting these options is done in the /etc/audit/syslog.conf file on the args line. If it is desired that events are interpreted, add the word .B interpret to the args line. This will cause all events to be interpreted. The drawback to this approach is that naive parsers can be tricked by an adversary that has the ability to name files, processes, or other user controlled objects. If you are aggregating multiple machines, you should edit auditd.conf to set the name_format to something meaningful and the log_format to enriched. This way you can tell where the event came from and have the user name and groups resolved locally before it is sent off of the machine. .SH FILES /etc/audit/plugins/syslog.conf /etc/audit/auditd.conf .SH "SEE ALSO" .BR auditd.conf (8), .BR auditd-plugins (5), .BR syslog (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/audisp/plugins/syslog/audisp-syslog.c000066400000000000000000000152411501761310600240560ustar00rootroot00000000000000/* audisp-syslog.c -- * Copyright 2018 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #ifdef HAVE_LIBCAP_NG #include #endif #include "libaudit.h" #include "common.h" // FIXME temporary #include "auparse.h" /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static int priority; static int interpret = 0; /* * SIGTERM handler */ static void term_handler( int sig ) { stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler( int sig ) { hup = 1; } static void reload_config(void) { hup = 0; } static int init_syslog(int argc, const char *argv[]) { int i, facility = LOG_USER; priority = LOG_INFO; for (i = 1; i < argc; i++) { if (argv[i]) { if (strcasecmp(argv[i], "LOG_DEBUG") == 0) priority = LOG_DEBUG; else if (strcasecmp(argv[i], "LOG_INFO") == 0) priority = LOG_INFO; else if (strcasecmp(argv[i], "LOG_NOTICE") == 0) priority = LOG_NOTICE; else if (strcasecmp(argv[i], "LOG_WARNING") == 0) priority = LOG_WARNING; else if (strcasecmp(argv[i], "LOG_ERR") == 0) priority = LOG_ERR; else if (strcasecmp(argv[i], "LOG_CRIT") == 0) priority = LOG_CRIT; else if (strcasecmp(argv[i], "LOG_ALERT") == 0) priority = LOG_ALERT; else if (strcasecmp(argv[i], "LOG_EMERG") == 0) priority = LOG_EMERG; else if (strcasecmp(argv[i], "LOG_LOCAL0") == 0) facility = LOG_LOCAL0; else if (strcasecmp(argv[i], "LOG_LOCAL1") == 0) facility = LOG_LOCAL1; else if (strcasecmp(argv[i], "LOG_LOCAL2") == 0) facility = LOG_LOCAL2; else if (strcasecmp(argv[i], "LOG_LOCAL3") == 0) facility = LOG_LOCAL3; else if (strcasecmp(argv[i], "LOG_LOCAL4") == 0) facility = LOG_LOCAL4; else if (strcasecmp(argv[i], "LOG_LOCAL5") == 0) facility = LOG_LOCAL5; else if (strcasecmp(argv[i], "LOG_LOCAL6") == 0) facility = LOG_LOCAL6; else if (strcasecmp(argv[i], "LOG_LOCAL7") == 0) facility = LOG_LOCAL7; else if (strcasecmp(argv[i], "LOG_AUTH") == 0) facility = LOG_AUTH; else if (strcasecmp(argv[i], "LOG_AUTHPRIV") == 0) facility = LOG_AUTHPRIV; else if (strcasecmp(argv[i], "LOG_DAEMON") == 0) facility = LOG_DAEMON; else if (strcasecmp(argv[i], "LOG_SYSLOG") == 0) facility = LOG_SYSLOG; else if (strcasecmp(argv[i], "LOG_USER") == 0) facility = LOG_USER; else if (strcasecmp(argv[i], "interpret") == 0) interpret = 1; else { syslog(LOG_ERR, "Unknown log priority/facility %s", argv[i]); return 1; } } } syslog(LOG_INFO, "syslog plugin initialized with facility %d and priority %d", facility, priority); if (facility != LOG_USER) openlog("audispd", 0, facility); return 0; } static char *record = NULL; static inline void write_syslog(char *s) { if (interpret) { int rc, header = 0; char *mptr, tbuf[64]; // Setup record buffer if (record == NULL) record = malloc(MAX_AUDIT_MESSAGE_LENGTH); if (record == NULL) return; auparse_state_t *au = auparse_init(AUSOURCE_BUFFER, s); if (au == NULL) return; rc = auparse_first_record(au); // AUDIT_EOE has no fields - drop it if (auparse_get_num_fields(au) == 0) { auparse_destroy(au); return; } // Now iterate over the fields and print each one mptr = record; while (rc > 0 && ((mptr-record) < (MAX_AUDIT_MESSAGE_LENGTH-128))) { int ftype = auparse_get_field_type(au); const char *fname = auparse_get_field_name(au); const char *fval; switch (ftype) { case AUPARSE_TYPE_ESCAPED_FILE: fval = auparse_interpret_realpath(au); break; case AUPARSE_TYPE_SOCKADDR: fval = auparse_interpret_sock_address(au); if (fval == NULL) fval = auparse_interpret_sock_family(au); break; default: fval = auparse_interpret_field(au); break; } mptr = stpcpy(mptr, fname ? fname : "?"); mptr = stpcpy(mptr, "="); mptr = stpcpy(mptr, fval ? fval : "?"); mptr = stpcpy(mptr, " "); rc = auparse_next_field(au); if (!header && fname && strcmp(fname, "type") == 0) { mptr = stpcpy(mptr, "msg=audit("); time_t t = auparse_get_time(au); struct tm *tv = localtime(&t); if (tv) strftime(tbuf, sizeof(tbuf), "%x %T", tv); else strcpy(tbuf, "?"); mptr = stpcpy(mptr, tbuf); mptr = stpcpy(mptr, ") : "); header = 1; } } // Record is complete, dump it to syslog syslog(priority, "%s", record); auparse_destroy(au); } else { char *c = strchr(s, AUDIT_INTERP_SEPARATOR); if (c) *c = ' '; syslog(priority, "%s", s); } } int main(int argc, const char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH+1]; struct sigaction sa; if (init_syslog(argc, argv)) return 1; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); #ifdef HAVE_LIBCAP_NG // Drop capabilities capng_clear(CAPNG_SELECT_BOTH); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "audisp-syslog plugin was unable to drop capabilities, continuing with elevated priviles"); #endif do { fd_set read_mask; int retval = -1; /* Load configuration */ if (hup) { reload_config(); } do { FD_ZERO(&read_mask); FD_SET(0, &read_mask); retval= select(1, &read_mask, NULL, NULL, NULL); } while (retval == -1 && errno == EINTR && !hup && !stop); /* Now the event loop */ if (!stop && !hup && retval > 0) { if (FD_ISSET(0, &read_mask)) { do { if (audit_fgets(tmp, MAX_AUDIT_MESSAGE_LENGTH, 0) > 0) write_syslog(tmp); } while (audit_fgets_more( MAX_AUDIT_MESSAGE_LENGTH)); } } if (audit_fgets_eof()) break; } while (stop == 0); free(record); return 0; } audit-userspace-4.0.5/audisp/plugins/syslog/syslog.conf000066400000000000000000000010111501761310600232640ustar00rootroot00000000000000# This file controls the configuration of the syslog plugin. # It simply takes events and writes them to syslog. The # arguments provided can be the default priority that you # want the events written with. And optionally, you can give # a second argument indicating the facility that you want events # logged to. Valid options are LOG_LOCAL0 through 7, LOG_AUTH, # LOG_AUTHPRIV, LOG_DAEMON, LOG_SYSLOG, and LOG_USER. active = no direction = out path = /sbin/audisp-syslog type = always args = LOG_INFO format = string audit-userspace-4.0.5/audisp/plugins/zos-remote/000077500000000000000000000000001501761310600216705ustar00rootroot00000000000000audit-userspace-4.0.5/audisp/plugins/zos-remote/Makefile.am000066400000000000000000000042121501761310600237230ustar00rootroot00000000000000# Makefile.am-- # Copyright (C) 2007,2008 International Business Machines Corp. # Copyright (C) 2011, 2015 Red Hat. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Klaus Heinrich Kiwi # AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/auparse CONFIG_CLEAN_FILES = *.rej *.orig EXTRA_DIST = zos-remote.conf audispd-zos-remote.conf plugin_confdir=$(sysconfdir)/audit plugin_conf = zos-remote.conf dispatcher_confdir = $(plugin_confdir)/plugins.d dispatcher_conf = audispd-zos-remote.conf sbin_PROGRAMS = audispd-zos-remote noinst_HEADERS = zos-remote-log.h zos-remote-ldap.h zos-remote-config.h \ zos-remote-queue.h audispd_zos_remote_SOURCES = zos-remote-plugin.c zos-remote-log.c \ zos-remote-ldap.c zos-remote-config.c zos-remote-queue.c audispd_zos_remote_CFLAGS = -W -Wall -Wundef -D_GNU_SOURCE -fPIE -DPIE ${WFLAGS} audispd_zos_remote_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now audispd_zos_remote_LDADD = -lpthread -lldap -llber $(CAPNG_LDADD) ${top_builddir}/auparse/libauparse.la audispd_zos_remote_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la install-data-hook: mkdir -p -m 0750 ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(plugin_conf) \ ${DESTDIR}${plugin_confdir} $(INSTALL_DATA) -D -m 640 ${srcdir}/$(dispatcher_conf) \ ${DESTDIR}${dispatcher_confdir} uninstall-hook: rm ${DESTDIR}${plugin_confdir}/$(plugin_conf) rm ${DESTDIR}${dispatcher_confdir}/$(dispatcher_conf) audit-userspace-4.0.5/audisp/plugins/zos-remote/audispd-zos-remote.conf000066400000000000000000000006621501761310600262760ustar00rootroot00000000000000# This is the configuration for the audispd-zos-remote # audit dispatcher plugin - See auditd(8) # # Note that this specific plugin has a configuration file of # its own. The complete path for this file must be entered as # the argument for the plugin in the 'args' field below # See audispd-zos-remote(8) active = no direction = out path = /sbin/audispd-zos-remote type = always args = /etc/audit/zos-remote.conf format = string audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-config.c000066400000000000000000000320701501761310600254050ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * * based on code by Steve Grubb * ***************************************************************************/ #include "zos-remote-config.h" #include #include #include #include #include #include #include #include #include "zos-remote-log.h" /* Local prototypes */ struct nv_pair { const char *name; const char *value; const char *option; }; struct kw_pair { const char *name; int (*parser) (struct nv_pair *, int, plugin_conf_t *); int max_options; }; struct nv_list { const char *name; int option; }; static char *get_line(FILE *, char *); static int nv_split(char *, struct nv_pair *); static const struct kw_pair *kw_lookup(const char *); static int server_parser(struct nv_pair *, int, plugin_conf_t *); static int port_parser(struct nv_pair *, int, plugin_conf_t *); static int timeout_parser(struct nv_pair *, int, plugin_conf_t *); static int user_parser(struct nv_pair *, int, plugin_conf_t *); static int password_parser(struct nv_pair *, int, plugin_conf_t *); static int q_depth_parser(struct nv_pair *, int, plugin_conf_t *); static int sanity_check(plugin_conf_t *); static const struct kw_pair keywords[] = { {"server", server_parser, 0}, {"port", port_parser, 0}, {"timeout", timeout_parser, 0}, {"user", user_parser, 0}, {"password", password_parser, 0}, {"q_depth", q_depth_parser, 0}, {NULL, NULL, 0} }; #define UNUSED(x) (void)(x) /* * Set everything to its default value */ void plugin_clear_config(plugin_conf_t * c) { c->server = NULL; c->port = 0; c->user = NULL; c->password = NULL; c->timeout = 15; c->q_depth = 64; /* not re-setting counter */ } int plugin_load_config(plugin_conf_t * c, const char *file) { int fd, rc, mode, lineno = 1; struct stat st; FILE *f; char buf[128]; plugin_clear_config(c); /* open the file */ mode = O_RDONLY; rc = open(file, mode); if (rc < 0) { if (errno != ENOENT) { log_err("Error opening %s (%s)", file, strerror(errno)); return 1; } log_warn("Config file %s doesn't exist, skipping", file); return 1; } fd = rc; /* check the file's permissions: owned by root, not world anything, * not symlink. */ if (fstat(fd, &st) < 0) { log_err("Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { log_err("Error - %s isn't owned by root", file); close(fd); return 1; } if ((st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP)) != (S_IRUSR | S_IWUSR | S_IRGRP)) { log_err("%s permissions should be 0640", file); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { log_err("Error - %s is not a regular file", file); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "r"); if (f == NULL) { log_err("Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf)) { /* convert line into name-value pair */ const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: /* fine */ break; case 1: /* not the right number of tokens. */ log_err("Wrong number of arguments for line %d in %s", lineno, file); break; case 2: /* no '=' sign */ log_err("Missing equal sign for line %d in %s", lineno, file); break; default: /* something else went wrong... */ log_err("Unknown error for line %d in %s", lineno, file); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { log_err("Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, file); fclose(f); return 1; } /* Check number of options */ if (kw->max_options == 0 && nv.option != NULL) { log_err("Keyword \"%s\" has invalid option " "\"%s\" in line %d of %s", nv.name, nv.option, lineno, file); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(&nv, lineno, c); if (rc != 0) { fclose(f); return 1; /* local parser puts message out */ } lineno++; } fclose(f); c->name = strdup(basename(file)); if (lineno > 1) return sanity_check(c); return 0; } static char *get_line(FILE * f, char *buf) { if (fgets_unlocked(buf, 128, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) *ptr = 0; return buf; } return NULL; } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr, *saved; nv->name = NULL; nv->value = NULL; nv->option = NULL; ptr = strtok_r(buf, " ", &saved); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = strtok_r(NULL, " ", &saved); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = strtok_r(NULL, " ", &saved); if (ptr == NULL) return 1; nv->value = ptr; /* See if there's an option */ ptr = strtok_r(NULL, " ", &saved); if (ptr) { nv->option = ptr; /* Make sure there's nothing else */ ptr = strtok_r(NULL, " ", &saved); if (ptr) return 1; } /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int server_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { UNUSED(line); if (nv->value == NULL) c->server = NULL; else c->server = strdup(nv->value); return 0; } static int port_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { const char *ptr = nv->value; unsigned long i; /* check that all chars are numbers */ for (i = 0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { log_err("Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { log_err("Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } c->port = i; return 0; } static int timeout_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { const char *ptr = nv->value; unsigned long i; /* check that all chars are numbers */ for (i = 0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { log_err("Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { log_err("Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } c->timeout = i; return 0; } static int user_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { UNUSED(line); if (nv->value == NULL) c->user = NULL; else c->user = strdup(nv->value); return 0; } static int password_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { UNUSED(line); if (nv->value == NULL) c->password = NULL; else c->password = strdup(nv->value); return 0; } static int q_depth_parser(struct nv_pair *nv, int line, plugin_conf_t * c) { const char *ptr = nv->value; unsigned long i; /* check that all chars are numbers */ for (i = 0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { log_err("Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { log_err("Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (i < 16 || i > 99999) { log_err("q_depth must be between 16 and 99999"); return 1; } c->q_depth = i; return 0; } /* * Check configuration.At this point, all fields have been read. * Returns 0 if no problems and 1 if problems detected. */ static int sanity_check(plugin_conf_t * c) { /* Error checking */ if (!c->server) { log_err("Error - no server hostname given"); return 1; } if (!c->user) { log_err("Error - no bind user given"); return 1; } if (!c->password) { log_err("Error - no password given"); return 1; } if (!c->timeout) { log_err("Error - timeout can't be zero"); return 1; } return 0; } void plugin_free_config(plugin_conf_t * c) { if (c == NULL) return; free((void *) c->server); free((void *) c->user); free((void *) c->password); free((void *) c->name); } audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-config.h000066400000000000000000000047131501761310600254150ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * * based on code by Steve Grubb * ***************************************************************************/ #ifndef _ZOS_REMOTE_CONFIG_H #define _ZOS_REMOTE_CONFIG_H /*************************************************************************** * z/OS Remote-services Plugin configuration * ***************************************************************************/ typedef struct plugin_conf { char *name; char *server; unsigned int port; char *user; char *password; long timeout; unsigned int q_depth; unsigned int counter; } plugin_conf_t; void plugin_clear_config(plugin_conf_t *); int plugin_load_config(plugin_conf_t *, const char *); void plugin_free_config(plugin_conf_t *); #endif /* _ZOS_REMOTE_CONFIG_H */ audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-ldap.c000066400000000000000000000573401501761310600250670ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * ***************************************************************************/ #include "zos-remote-ldap.h" #include #include #include #include #include "zos-remote-log.h" /*************************************************************************** * Audit response struct * ***************************************************************************/ typedef struct audit_resp_item { ber_int_t version; /* Version of Response data itself */ ber_int_t itemTag; /* Copy of itemTag from Operation */ ber_int_t majorCode; /* Majorcode. Main return code of this Outcome */ ber_int_t minorCode1; /* minorCode1. SAFRc or other Rc */ ber_int_t minorCode2; /* minorCode2. RacfRc or other Rc */ ber_int_t minorCode3; /* minorCode3. RacfRsn or other Rc */ } audit_resp_item_t; typedef struct audit_response { ber_int_t respVersion; /* Overall version */ ber_int_t respMajor; /* Overall major code */ unsigned int numItems; /* Number of response items */ audit_resp_item_t **itemList; /* response ItemList */ } audit_response_t; /*************************************************************************** * z/OS Remote-services Major return code handling * ***************************************************************************/ struct zos_remote_error { int code; char *str; }; static struct zos_remote_error zos_remote_errlist[] = { {ZOS_REMOTE_MAJOR_SUCCESS, "Success"}, {ZOS_REMOTE_MAJOR_WARNINGMODE, "WARNINGMODE - Event was logged, with warnings"}, {ZOS_REMOTE_MAJOR_NOTREQ, "NOTREQ - No logging required"}, {ZOS_REMOTE_MAJOR_UNDETERMINED, "UNDETERMINED - Undetermined result"}, {ZOS_REMOTE_MAJOR_UNAUTHORIZED, "UNAUTHORIZED - The user does not have authority the R_auditx service"}, {ZOS_REMOTE_MAJOR_RACROUTE, "RACROUTE - The R_auditx service returned an unexpected error"}, {ZOS_REMOTE_MAJOR_VAL_ERR, "VAL_ERR - Value error in request"}, {ZOS_REMOTE_MAJOR_ENC_ERR, "ENC_ERR - DER decoding error in request"}, {ZOS_REMOTE_MAJOR_UNSUF_AUTH, "UNSUF_AUTH - The user has insufficient authority for the requested function"}, {ZOS_REMOTE_MAJOR_EMPTY, "EMPTY - Empty request received - No items found within the ItemList"}, {ZOS_REMOTE_MAJOR_INVALID_VER, "INVALID_VER - Invalid RequestVersion"}, {ZOS_REMOTE_MAJOR_INTERNAL_ERR, "INTERNAL_ERR - An internal error was encountered within the ICTX component"}, {-1, NULL} }; /*************************************************************************** * Internal functions prototypes * ***************************************************************************/ static int _zos_remote_init(ZOS_REMOTE *); static void _zos_remote_destroy(ZOS_REMOTE *); static int zos_remote_connect(ZOS_REMOTE *); static void zos_remote_disconnect(ZOS_REMOTE *); static int submit_xop_s(ZOS_REMOTE *, struct berval *); static int decode_response(audit_response_t *, struct berval *); /*************************************************************************** * Exported functions * ***************************************************************************/ int submit_request_s(ZOS_REMOTE *zos_remote, BerElement *ber) { int rc, retry = 1; /* retry once and give up */ struct berval bv; rc = ber_flatten2(ber, &bv, 0); /* 0 = Use ber's buffer */ if (rc == -1) { log_err("Error flattening BER element"); return ICTX_E_ABORT; } retry: rc = submit_xop_s(zos_remote, &bv); switch (rc) { case ICTX_SUCCESS: break; case ICTX_E_TRYAGAIN: /* * Usually means that the server connection timed-out * So we flush the LDAP connection by unsetting the * 'connected' flag and trying again. */ if (retry > 0) { log_debug("Connection seems down - retrying"); retry--; _zos_remote_destroy(zos_remote); rc = _zos_remote_init(zos_remote); if (rc != ICTX_SUCCESS) log_err("Error - failed to re-initialize LDAP session"); else goto retry; /* go to submit_xop_s once more */ } log_err("Can't establish connection"); break; case ICTX_E_ABORT: break; default: log_err("Event resulted failure, code: 0x%x", rc); } return rc; } int zos_remote_init(ZOS_REMOTE *zos_remote, const char *server, int port, const char *user, const char *password, int timeout) { if (server == NULL || user == NULL || password == NULL) { log_err("Error: required parameters are not present in config file"); return ICTX_E_FATAL; } zos_remote->server = strdup(server); zos_remote->port = port; zos_remote->user = strdup(user); zos_remote->password = strdup(password); zos_remote->timeout = timeout; zos_remote->connected = 0; if (!zos_remote->server || !zos_remote->user || !zos_remote->password) { log_err("Error allocating memory for session members"); return ICTX_E_FATAL; } return _zos_remote_init(zos_remote); } void zos_remote_destroy(ZOS_REMOTE *zos_remote) { _zos_remote_destroy(zos_remote); free(zos_remote->server); free(zos_remote->user); free(zos_remote->password); } char *zos_remote_err2string(int err) { int i; for (i = 0; zos_remote_errlist[i].str != NULL; i++) { if (err == zos_remote_errlist[i].code) return zos_remote_errlist[i].str; } return "Unknown error"; } /*************************************************************************** * Internal Functions * ***************************************************************************/ static int _zos_remote_init(ZOS_REMOTE *zos_remote) { int version, rc; char *uri = NULL; #ifdef LDAP_DEPRECATED log_debug("Initializing z/OS Remote-services LDAP connection at ldap://%s:%d", zos_remote->server, zos_remote->port); zos_remote->ld = ldap_init(zos_remote->server zos_remote->port ? zos_remote->port : LDAP_PORT); if (zos_remote->ld == NULL) { log_err("Error initializing LDAP session: %s", strerror(errno)); rc = ICTX_E_FATAL; goto end; } #else /* build ldap URI */ if (zos_remote->port == 0 || zos_remote->port == LDAP_PORT) rc = asprintf(&uri, "ldap://%s", zos_remote->server); else rc = asprintf(&uri, "ldap://%s:%u", zos_remote->server, zos_remote->port); if (rc == -1) { log_err("Out of memory building LDAP server URI"); rc = ICTX_E_FATAL; uri = NULL; goto end; } log_debug("Initializing z/OS Remote-services LDAP connection at %s", uri); /* Get a handle to an LDAP connection */ rc = ldap_initialize(&zos_remote->ld, uri); if (rc != LDAP_SUCCESS) { log_err("Error initializing LDAP session: %s", ldap_err2string(rc)); rc = ICTX_E_FATAL; goto free_uri; } #endif /* * Ensure the LDAP protocol version supported by the client * to 3. (Extended operations are part of version 3). */ rc = ldap_get_option(zos_remote->ld, LDAP_OPT_PROTOCOL_VERSION, &version); if (rc != LDAP_OPT_SUCCESS) { log_err("Error getting LDAP session options"); rc = ICTX_E_FATAL; goto unbind; } if (version < LDAP_VERSION3) { log_debug("Setting LDAP session version to %d", LDAP_VERSION3); version = LDAP_VERSION3; rc = ldap_set_option(zos_remote->ld, LDAP_OPT_PROTOCOL_VERSION, &version); if (rc != LDAP_OPT_SUCCESS) { log_err("Error setting LDAP session version"); rc = ICTX_E_FATAL; goto unbind; } } goto free_uri; unbind: ldap_unbind_ext_s(zos_remote->ld, NULL, NULL); zos_remote->ld = NULL; free_uri: free(uri); end: return rc; } static void _zos_remote_destroy(ZOS_REMOTE *zos_remote) { zos_remote_disconnect(zos_remote); zos_remote->ld = NULL; } static int zos_remote_connect(ZOS_REMOTE *zos_remote) { struct berval cred; int rc; char bindusr[255]; snprintf(bindusr, 255, "racfid=%s,cn=ictx", zos_remote->user); log_debug("Attempting BIND. User '%s', password ''", bindusr); cred.bv_val = (char *) zos_remote->password; cred.bv_len = strlen(zos_remote->password); rc = ldap_sasl_bind_s(zos_remote->ld, bindusr, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL); switch (rc) { case LDAP_SUCCESS: log_debug("LDAP BIND succeeded"); zos_remote->connected = 1; rc = ICTX_SUCCESS; break; case LDAP_SERVER_DOWN: case LDAP_BUSY: case LDAP_UNAVAILABLE: case LDAP_TIMEOUT: case LDAP_CONNECT_ERROR: log_warn("z/OS Remote-services connection failed: %s", ldap_err2string(rc)); rc = ICTX_E_TRYAGAIN; break; default: log_err("Error - z/OS Remote-services initialization failed: %s", ldap_err2string(rc)); rc = ICTX_E_FATAL; } return rc; } static void zos_remote_disconnect(ZOS_REMOTE *zos_remote) { if (zos_remote->ld) { log_debug("Unbinding LDAP session"); #ifdef LDAP_DEPRECATED ldap_unbind(zos_remote->ld); #else ldap_unbind_ext_s(zos_remote->ld, NULL, NULL); #endif } zos_remote->connected = 0; } /* * Sync-submit extended operation given in *bv * return ICTX_SUCCESS if submission (and response) * succeeded. * Log errors using log_err() functions */ int submit_xop_s(ZOS_REMOTE *zos_remote, struct berval *bv) { LDAPMessage *result; audit_response_t response; int rc, errcode, msgId; unsigned int i; char *errmsg, *oid; struct berval *bv_response; struct timeval t; if (zos_remote->connected == 0) { rc = zos_remote_connect(zos_remote); if (rc != ICTX_SUCCESS) return rc; } /* call LDAP - won't block */ rc = ldap_extended_operation(zos_remote->ld, ICTX_OIDAUDITREQUEST, bv, NULL, NULL, &msgId); if (rc == LDAP_SERVER_DOWN) { zos_remote->connected = 0; return ICTX_E_TRYAGAIN; } else if (rc != LDAP_SUCCESS) { log_err("LDAP extended operation submission failure: %s", ldap_err2string(rc)); return ICTX_E_ABORT; } else { log_debug("Sent LDAP extended operation request, msgId=0x%x", msgId); } /* call blocking ldap_result with specified timeout */ t.tv_sec = zos_remote->timeout; t.tv_usec = 0; rc = ldap_result(zos_remote->ld, msgId, 1, &t, &result); if (rc == -1) { /* error in ldap operation */ ldap_get_option(zos_remote->ld, LDAP_OPT_ERROR_NUMBER, &errcode); switch (errcode) { case LDAP_SERVER_DOWN: /* Connection may have timed out, let's retry */ zos_remote->connected = 0; rc = ICTX_E_TRYAGAIN; break; default: log_err("ldap_result unexpected failure: %s (0x%x)", ldap_err2string(rc), rc); rc = ICTX_E_ABORT; } goto end; } else if (rc == 0) { /* timeout reached */ log_warn("LDAP extended operation timed out"); rc = ICTX_E_ABORT; goto end; } else if (rc != LDAP_RES_EXTENDED) { /* not an extended operation response! */ log_err("LDAP extended operation resulted in unexpected answer: 0x%x", rc); rc = ICTX_E_ABORT; goto free_result; } log_debug("Got LDAP Extended result"); /* * we have an extended operation result * first parse_result will check for errcode, later * parse_extended_result will give us the oid and the BER value */ rc = ldap_parse_result(zos_remote->ld, result, &errcode, NULL, &errmsg, NULL, NULL, 0); if (rc != LDAP_SUCCESS) { log_err("LDAP parse result internal failure (code 0x%x)", rc); rc = ICTX_E_ABORT; goto free_result; } if (errcode != LDAP_SUCCESS) { log_err("LDAP extended operation failed: %s", errmsg); rc = ICTX_E_ABORT; goto free_errmsg; } rc = ldap_parse_extended_result(zos_remote->ld, result, &oid, &bv_response, 0); if (rc != LDAP_SUCCESS) { log_err("Failed to parse ldap extended result (code 0x%x)", rc); rc = ICTX_E_ABORT; goto free_errmsg; } if (oid && strcmp(oid, ICTX_OIDAUDITRESPONSE) != 0) { /* oid == null shouldn't be a problem to log_err */ log_err("LDAP extended operation returned an invalid oid: %s", oid); rc = ICTX_E_ABORT; goto free_bv; } rc = decode_response(&response, bv_response); if (rc != ICTX_SUCCESS) { log_err("Error decoding extended operation response"); goto free_bv; } if (response.respMajor == ZOS_REMOTE_MAJOR_SUCCESS) { /* submission was successful, no further processing needed */ log_debug("Successfully submitted Remote audit Request"); rc = ICTX_SUCCESS; goto free_response; } else if (response.respMajor == ZOS_REMOTE_MAJOR_EMPTY) { /* something is going on. Set error and stop processing */ log_warn("Warning - LDAP extended operation returned empty result"); rc = ICTX_E_ABORT; goto free_response; } else if (response.respMajor == ZOS_REMOTE_MAJOR_WARNINGMODE || response.respMajor == ZOS_REMOTE_MAJOR_NOTREQ) rc = ICTX_SUCCESS; /* don't fail, but continue processing */ else rc = ICTX_E_ABORT; /* set return code and continue processing */ /* If it's not success nor empty, let's check for errors in the response */ for (i = 0; i < response.numItems; i++) { switch ((response.itemList[i])->majorCode) { /* 0 <= Major Code <= 14 */ case ZOS_REMOTE_MAJOR_SUCCESS: break; case ZOS_REMOTE_MAJOR_WARNINGMODE: case ZOS_REMOTE_MAJOR_NOTREQ: log_debug("Warning - LDAP extended operation returned '%s' for item %d", zos_remote_err2string((response.itemList[i])->majorCode), (response.itemList[i])->itemTag); log_debug("SAF code: 0x%x, RACF code: 0x%x, RACF reason: 0x%x", (response.itemList[i])->minorCode1, (response.itemList[i])->minorCode2, (response.itemList[i])->minorCode3); break; case ZOS_REMOTE_MAJOR_UNDETERMINED: case ZOS_REMOTE_MAJOR_UNAUTHORIZED: case ZOS_REMOTE_MAJOR_RACROUTE: log_err("Error - LDAP extended operation returned '%s' for item %d", zos_remote_err2string((response.itemList[i])->majorCode), (response.itemList[i])->itemTag); log_err("SAF code: 0x%x, RACF code: 0x%x, RACF reason: 0x%x", (response.itemList[i])->minorCode1, (response.itemList[i])->minorCode2, (response.itemList[i])->minorCode3); break; /* 16 <= Major Code <= 20 */ case ZOS_REMOTE_MAJOR_VAL_ERR: case ZOS_REMOTE_MAJOR_ENC_ERR: log_err("Error - LDAP extended operation returned '%s' for item %d", zos_remote_err2string((response.itemList[i])->majorCode), (response.itemList[i])->itemTag); log_err("Item field: %d, reason %d", (response.itemList[i])-> minorCode1, (response.itemList[i])->minorCode2); break; /* 24 <= Major code <= 100 */ case ZOS_REMOTE_MAJOR_UNSUF_AUTH: case ZOS_REMOTE_MAJOR_EMPTY: case ZOS_REMOTE_MAJOR_INVALID_VER: case ZOS_REMOTE_MAJOR_INTERNAL_ERR: log_err("Error - LDAP extended operation returned '%s' for item %d", zos_remote_err2string((response.itemList[i])->majorCode), (response.itemList[i])->itemTag); break; default: log_err("Error - LDAP extended operation returned an unknown Major code for item %d", (response.itemList[i])->majorCode); } } free_response: for (; response.numItems > 0; response.numItems--) free(response.itemList[response.numItems - 1]); free(response.itemList); free_bv: if (bv_response) ber_bvfree(bv_response); if (oid) ldap_memfree(oid); free_errmsg: ldap_memfree(errmsg); free_result: ldap_msgfree(result); end: return rc; } static int decode_response(audit_response_t * r, struct berval *bv) { BerElement *ber; ber_len_t len; int rc; if (!bv) { log_err("LDAP extended operation returned NULL message"); return ICTX_E_ABORT; } else if ((ber = ber_init(bv)) == NULL) { log_err("Error initializing BER response data"); return ICTX_E_ABORT; } log_debug("---Got an encoded request response:"); debug_bv(bv); r->respVersion = 0; r->respMajor = 0; r->numItems = 0; r->itemList = NULL; rc = ber_scanf(ber, "{ii", &r->respVersion, &r->respMajor); if (r->respVersion != ICTX_REQUESTVER) { log_err("Invalid version returned by z/OS Remote-services server"); log_err("Should be %d, got %d", ICTX_REQUESTVER, r->respVersion); rc = ICTX_E_ABORT; goto free_ber; } if (r->respMajor == ZOS_REMOTE_MAJOR_SUCCESS || r->respMajor == ZOS_REMOTE_MAJOR_EMPTY) { rc = ICTX_SUCCESS; /* No further processing required */ goto free_ber; } /* Inspect ber response otherwise */ while (ber_peek_tag(ber, &len) == LBER_SEQUENCE) { r->numItems++; r->itemList = (audit_resp_item_t **) realloc(r->itemList, r->numItems * sizeof (audit_resp_item_t *)); if (errno == ENOMEM) { if (r->itemList) free(r->itemList); rc = ICTX_E_FATAL; goto free_ber; } audit_resp_item_t *item = (audit_resp_item_t *) malloc(sizeof(audit_resp_item_t)); if (!item) { rc = ICTX_E_FATAL; goto free_ber; } rc |= ber_scanf(ber, "{{iiiiii}}", &item->version, &item->itemTag, &item->majorCode, &item->minorCode1, &item->minorCode2, &item->minorCode3); r->itemList[r->numItems - 1] = item; } rc |= ber_scanf(ber, "}"); if (rc == -1) { for (; r->numItems > 0; r->numItems--) free(r->itemList[r->numItems - 1]); free(r->itemList); rc = ICTX_E_ABORT; } else rc = ICTX_SUCCESS; free_ber: ber_free(ber, 1); return rc; } audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-ldap.h000066400000000000000000000333631501761310600250730ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * ***************************************************************************/ #ifndef _ZOS_REMOTE_LDAP_H #define _ZOS_REMOTE_LDAP_H #include #include /*************************************************************************** * LDAP Extended Op OID for ICTX Audit * ***************************************************************************/ /* ICTX EIM component AUDIT Request OID */ #define ICTX_OIDAUDITREQUEST "1.3.18.0.2.12.68" /* The AUDIT Response OID */ #define ICTX_OIDAUDITRESPONSE "1.3.18.0.2.12.69" /* This implementation version Request and response must match this */ #define ICTX_REQUESTVER 0x1 /* Needed for BER-encoding */ #define ASN1_IA5STRING_TAG 0x16 /*************************************************************************** * the ASN.1 struct for the remote audit request and response: * * * * RequestValue ::= SEQUENCE { * * RequestVersion INTEGER, * * ItemList SEQUENCE OF * * Item SEQUENCE { * * ItemVersion INTEGER, * * ItemTag INTEGER, * * LinkValue OCTET STRING SIZE(8), * * Violation BOOLEAN, * * Event INTEGER, * * Qualifier INTEGER, * * Class IA5String, * * Resource IA5String, * * LogString IA5String, * * DatafieldList SEQUENCE OF * * DataField SEQUENCE { * * TYPE INTEGER, * * VALUE IA5STRING * * } * * } * * } * * * * Response ::= SEQUENCE { * * Version INTEGER, * * ResponseCode INTEGER, * * ItemList SEQUENCE OF * * Item SEQUENCE { * * ItemVersion INTEGER, * * ItemTag INTEGER, * * MajorCode INTEGER, * * MinorCode1 INTEGER, * * MinorCode2 INTEGER, * * MinorCode3 INTEGER * * } * * } * ***************************************************************************/ /*************************************************************************** * z/OS Remote-services Audit Minor return codes meaning Major Code Meaning ---------- --------------------------------------------------------- 0-14 - MinorCode1 is the SAF return code - MinorCode2 is the RACF return code - MinorCode3 is the RACF reason code 16-20 - MinorCode1 identifies the extended operation request parameter number (see audit request ASN.1 definition): 0 - Item 1 - ItemVersion 2 - ItemTag 3 - LinkValue 4 - Violation 5 - Event 6 - Qualifier 7 - Class 8 - Resource 9 - LogString 10 - DataFieldList 11 - DataField * 12 - TYPE * 13 - VALUE * - MinorCode2 indicates one of the Following: 32 - incorrect length 36 - incorrect value 40 - encoding error - MinorCode3 has no defined meaning 24-100 - MinorCode1 has no defined meaning - MinorCode2 has no defined meaning - MinorCode3 has no defined meaning * There can be multiple DataField, TYPEs and VALUEs in a request. If any of them is bad you get the same 11, 12 or 13 MinorCode1. There is no further breakdown of which one is bad. ***************************************************************************/ /*************************************************************************** * Audit Request 'event' field meaning * ***************************************************************************/ #define ZOS_REMOTE_EVENT_AUTHENTICATION 0x1 #define ZOS_REMOTE_EVENT_AUTHORIZATION 0x2 #define ZOS_REMOTE_EVENT_AUTHORIZATION_MAPPING 0x3 #define ZOS_REMOTE_EVENT_KEY_MGMT 0x4 #define ZOS_REMOTE_EVENT_POLICY_MGMT 0x5 #define ZOS_REMOTE_EVENT_ADMIN_CONFIG 0x6 #define ZOS_REMOTE_EVENT_ADMIN_ACTION 0x7 /*************************************************************************** * Audit Request 'qualifier' field meaning * ***************************************************************************/ #define ZOS_REMOTE_QUALIF_SUCCESS 0x0 #define ZOS_REMOTE_QUALIF_INFO 0x1 #define ZOS_REMOTE_QUALIF_WARN 0x2 #define ZOS_REMOTE_QUALIF_FAIL 0x3 /*************************************************************************** * Relocate types for Audit Request * ***************************************************************************/ /* SAF identifier for bind user */ #define ZOS_REMOTE_RELOC_SAF_BIND_USER 100 /* Reguestor's bind user identifier */ #define ZOS_REMOTE_RELOC_REQ_BIND_USER 101 /* Originating security domain */ #define ZOS_REMOTE_RELOC_ORIG_SECURITY 102 /* Originating registry / realm */ #define ZOS_REMOTE_RELOC_ORIG_REALM 103 /* Originating user name */ #define ZOS_REMOTE_RELOC_ORIG_USER 104 /* Mapped security domain */ #define ZOS_REMOTE_RELOC_MAPPED_SECURITY 105 /* Mapped registry / realm */ #define ZOS_REMOTE_RELOC_MAPPED_REALM 106 /* Mapped user name */ #define ZOS_REMOTE_RELOC_MAPPED_USER 107 /* Operation performed */ #define ZOS_REMOTE_RELOC_OPERATION 108 /* Mechanism / object name */ #define ZOS_REMOTE_RELOC_OBJECT 109 /* Method / function used */ #define ZOS_REMOTE_RELOC_FUNCTION 110 /* Key / certificate name */ #define ZOS_REMOTE_RELOC_CERTIFICATE 111 /* Caller subject initiating security event */ #define ZOS_REMOTE_RELOC_INITIATING_EVENT 112 /* Date and time security event occurred */ #define ZOS_REMOTE_RELOC_TIMESTAMP 113 /* Application specific data. (i.e. Other) */ #define ZOS_REMOTE_RELOC_OTHER 114 /*************************************************************************** * z/OS Remote-services Audit Major return codes * ***************************************************************************/ #define ZOS_REMOTE_MAJOR_SUCCESS 0 /* Event was logged, with warnings */ #define ZOS_REMOTE_MAJOR_WARNINGMODE 2 /* No logging required No audit controls are set to require it */ #define ZOS_REMOTE_MAJOR_NOTREQ 3 /* Class not active/ractlisted, covering profile not found or RACF is not installed */ #define ZOS_REMOTE_MAJOR_UNDETERMINED 4 /* The user does not have authority the R_auditx service. The userid associated with the LDAP server must have at least READ access to the FACILITY class profile IRR.RAUDITX. */ #define ZOS_REMOTE_MAJOR_UNAUTHORIZED 8 /* The R_auditx service returned an unexpected error. Compare the returned minor codes with the SAF RACF codes documented in Security Server Callable Services */ #define ZOS_REMOTE_MAJOR_RACROUTE 12 /* A value specified in the extended operation request is incorrect or unsupported. Check the returned minor codes to narrow the reason */ #define ZOS_REMOTE_MAJOR_VAL_ERR 16 /* A DER decoding error was encountered in an item. Processing Terminated. Partial results may be returned */ #define ZOS_REMOTE_MAJOR_ENC_ERR 20 /* The requestor does not have sufficient authority for the requested function. The userid associated with the LDAP bind user must have at least READ access to the FACILITY class profile IRR.LDAP.REMOTE.AUDIT. */ #define ZOS_REMOTE_MAJOR_UNSUF_AUTH 24 /* No items are found within the ItemList sequence of the extended operation request, so no response items are returned */ #define ZOS_REMOTE_MAJOR_EMPTY 28 /* Invalid RequestVersion */ #define ZOS_REMOTE_MAJOR_INVALID_VER 61 /* An internal error was encountered within the ICTX component */ #define ZOS_REMOTE_MAJOR_INTERNAL_ERR 100 /*************************************************************************** * Some standard sizes for remote audit request items * ***************************************************************************/ #define ZOS_REMOTE_LINK_VALUE_SIZE 8 #define ZOS_REMOTE_CLASS_SIZE 8 #define ZOS_REMOTE_RESOURCE_SIZE 240 #define ZOS_REMOTE_LOGSTRING_SIZE 200 /*************************************************************************** * Some standard Error defines * ***************************************************************************/ #define ICTX_SUCCESS 0x00 /* maybe a temporary failure? */ #define ICTX_E_TRYAGAIN 0x01 /* permanent failure - abort event submission */ #define ICTX_E_ABORT 0x02 /* Fatal failure - abort program */ #define ICTX_E_FATAL 0x03 /* generic error */ #define ICTX_E_ERROR 0x10 /*************************************************************************** * structure representing an z/OS Remote-services session * ***************************************************************************/ typedef struct opaque { char *server; unsigned int port; char *user; char *password; unsigned int timeout; LDAP *ld; int connected; } ZOS_REMOTE; /*************************************************************************** * LDAP XOP operations * ***************************************************************************/ /* * Initializes z/OS Remote-services (LDAP to ITDS) connection, * binds to ITDS Server using configured RACF ID * Args are: * server, bind user, bind password, server port, timeout * Caller must call zos_remote_destroy() to free memory allocation */ int zos_remote_init(ZOS_REMOTE *, const char *, int, const char *, const char *, int); /* * Uninitializes z/OS Remote-services (LDAP) connection */ void zos_remote_destroy(ZOS_REMOTE *); /* * sync submit request - possibly reconnect to server * if the connection if found to be dead */ int submit_request_s(ZOS_REMOTE *, BerElement *); #endif /* _ZOS_REMOTE_LDAP_H */ audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-log.c000066400000000000000000000066071501761310600247300ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * ***************************************************************************/ #include "zos-remote-log.h" #include #include #include #include "auparse.h" static void vlog_prio(int prio, const char *fmt, va_list ap) { char *str; if (asprintf(&str, "pid=%d: %s", mypid, fmt) != -1) { vsyslog(LOG_DAEMON | prio, str, ap); free(str); } } void log_err(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vlog_prio(LOG_ERR, fmt, ap); va_end(ap); } void log_warn(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vlog_prio(LOG_WARNING, fmt, ap); va_end(ap); } void log_info(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vlog_prio(LOG_INFO, fmt, ap); va_end(ap); } void _log_debug(const char *fmt, ...) { va_list ap; va_start(ap, fmt); vlog_prio(LOG_INFO, fmt, ap); va_end(ap); } void _debug_ber(BerElement * ber) { struct berval bv; if (ber_flatten2(ber, &bv, 0) != -1) { debug_bv(&bv); } } void _debug_bv(struct berval *bv) { char *out; char octet[4]; ber_len_t i; log_debug("---BER value HEX dump (size %u bytes)", (unsigned int) bv->bv_len); if (bv->bv_len > 0) { out = (char *) calloc((3 * (bv->bv_len)) + 1, sizeof(char)); if (!out) return; for (i = 1; i <= bv->bv_len; i++) { snprintf(octet, 4, "%02x ", (unsigned char) bv->bv_val[i - 1]); strcat(out, octet); } log_debug(out); free(out); } } audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-log.h000066400000000000000000000046071501761310600247330ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * ***************************************************************************/ #ifndef _ZOS_REMOTE_LOG_H #define _ZOS_REMOTE_LOG_H #include "zos-remote-ldap.h" #include #include #include #include extern pid_t mypid; void log_err(const char *, ...); void log_warn(const char *, ...); void log_info(const char *, ...); void _log_debug(const char *, ...); void _debug_bv(struct berval *); void _debug_ber(BerElement *); #ifdef DEBUG #define log_debug(fmt, ...) _log_debug(fmt, ## __VA_ARGS__) #define debug_bv(bv) _debug_bv(bv) #define debug_ber(ber) _debug_ber(ber) #else #define log_debug(fmt, ...) #define debug_bv(bv) #define debug_ber(ber) #endif /* DEBUG */ #endif /* _ZOS_REMOTE_LOG_H */ audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-plugin.c000066400000000000000000000515541501761310600254460ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * ***************************************************************************/ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBCAP_NG #include #endif #include "auparse.h" #include "zos-remote-log.h" #include "zos-remote-ldap.h" #include "zos-remote-config.h" #include "zos-remote-queue.h" #define UNUSED(x) (void)(x) /* * Global vars */ volatile int stop = 0; volatile int hup = 0; static ZOS_REMOTE zos_remote_inst; static plugin_conf_t conf; static const char *def_config_file = "/etc/audit/zos-remote.conf"; static pthread_t submission_thread; pid_t mypid = 0; /* * SIGTERM handler */ static void term_handler(int sig) { UNUSED(sig); log_info("Got Termination signal - shutting down plugin"); stop = 1; nudge_queue(); } /* * SIGHUP handler - re-read config, reconnect to ITDS */ static void hup_handler(int sig) { UNUSED(sig); log_info("Got Hangup signal - flushing plugin configuration"); hup = 1; nudge_queue(); } /* * SIGALRM handler - help force exit when terminating daemon */ static void alarm_handler(int sig) { UNUSED(sig); log_err("Timeout waiting for submission thread - Aborting (some events may have been dropped)"); pthread_cancel(submission_thread); } /* * The submission thread * It's job is to dequeue the events from the queue * and sync submit them to ITDS */ static void *submission_thread_main(void *arg) { int rc; UNUSED(arg); log_debug("Starting event submission thread"); rc = zos_remote_init(&zos_remote_inst, conf.server, conf.port, conf.user, conf.password, conf.timeout); if (rc != ICTX_SUCCESS) { log_err("Error - Failed to initialize session to z/OS ITDS Server"); stop = 1; return 0; } while (stop == 0) { /* block until we have an event */ BerElement *ber = dequeue(); if (ber == NULL) { if (hup) { break; } continue; } debug_ber(ber); rc = submit_request_s(&zos_remote_inst, ber); if (rc == ICTX_E_FATAL) { log_err("Error - Fatal error in event submission. Aborting"); stop = 1; } else if (rc != ICTX_SUCCESS) { log_warn("Warning - Event submission failure - event dropped"); } else { log_debug("Event submission success"); } ber_free(ber, 1); /* also free BER buffer */ } log_debug("Stopping event submission thread"); zos_remote_destroy(&zos_remote_inst); return 0; } /* * auparse library callback that's called when an event is ready */ void push_event(auparse_state_t * au, auparse_cb_event_t cb_event_type, void *user_data) { int rc; BerElement *ber; int qualifier; char timestamp[26]; char linkValue[ZOS_REMOTE_LINK_VALUE_SIZE]; char logString[ZOS_REMOTE_LOGSTRING_SIZE]; unsigned long linkValue_tmp; UNUSED(user_data); if (cb_event_type != AUPARSE_CB_EVENT_READY) return; const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) return; /* * we have an event. Each record will result in a different 'Item' * (refer ASN.1 definition in zos-remote-ldap.h) */ /* * Create a new BER element to encode the request */ ber = ber_alloc_t(LBER_USE_DER); if (ber == NULL) { log_err("Error allocating memory for BER element"); goto fatal; } /* * Collect some information to fill in every item */ const char *node = auparse_get_node(au); const char *orig_type = auparse_find_field(au, "type"); /* roll back event to get 'success' */ auparse_first_record(au); const char *success = auparse_find_field(au, "success"); /* roll back event to get 'res' */ auparse_first_record(au); const char *res = auparse_find_field(au, "res"); /* check if this event is a success or failure one */ if (success) { if (strncmp(success, "0", 1) == 0 || strncmp(success, "no", 2) == 0) qualifier = ZOS_REMOTE_QUALIF_FAIL; else qualifier = ZOS_REMOTE_QUALIF_SUCCESS; } else if (res) { if (strncmp(res, "0", 1) == 0 || strncmp(res, "failed", 6) == 0) qualifier = ZOS_REMOTE_QUALIF_FAIL; else qualifier = ZOS_REMOTE_QUALIF_SUCCESS; } else qualifier = ZOS_REMOTE_QUALIF_INFO; /* get timestamp text */ ctime_r(&e->sec, timestamp); timestamp[24] = '\0'; /* strip \n' */ /* prepare linkValue which will be used for every item */ linkValue_tmp = htonl(e->serial); /* padronize to use network * byte order */ memset(&linkValue, 0, ZOS_REMOTE_LINK_VALUE_SIZE); memcpy(&linkValue, &linkValue_tmp, sizeof(unsigned long)); /* * Prepare the logString with some meaningful text * We assume the first record type found is the * 'originating' audit record */ sprintf(logString, "Linux (%s): type: %s", node, orig_type); free((void *)node); /* * Start writing to BER element. * There's only one field (version) out of the item sequence. * Also open item sequence */ rc = ber_printf(ber, "{i{", ICTX_REQUESTVER); if (rc < 0) goto skip_event; /* * Roll back to first record and iterate through all records */ auparse_first_record(au); do { const char *type = auparse_find_field(au, "type"); if (type == NULL) goto skip_event; log_debug("got record: %s", auparse_get_record_text(au)); /* * First field is item Version, same as global version */ rc = ber_printf(ber, "{i", ICTX_REQUESTVER); /* * Second field is the itemTag * use our internal event counter, increasing it */ rc |= ber_printf(ber, "i", conf.counter++); /* * Third field is the linkValue * using ber_put_ostring since it is not null-terminated */ rc |= ber_put_ostring(ber, linkValue, ZOS_REMOTE_LINK_VALUE_SIZE, LBER_OCTETSTRING); /* * Fourth field is the violation * Don't have anything better yet to put here */ rc |= ber_printf(ber, "b", 0); /* * Fifth field is the event. * FIXME: this might be the place to switch on the * audit record type and map to a more meaningful * SMF type 83, subtype 4 event here */ rc |= ber_printf(ber, "i", ZOS_REMOTE_EVENT_AUTHORIZATION); /* * Sixth field is the qualifier. We map 'success' or * 'res' to this field */ rc |= ber_printf(ber, "i", qualifier); /* * Seventh field is the Class * always use '@LINUX' for this version * max size ZOS_REMOTE_CLASS_SIZE */ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG); rc |= ber_printf(ber, "s", "@LINUX"); /* * Eighth field is the resource * use the record type (name) as the resource * max size ZOS_REMOTE_RESOURCE_SIZE */ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG); rc |= ber_printf(ber, "s", type); /* * Ninth field is the LogString * we try to put something meaningful here * we also start the relocations sequence */ rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG); rc |= ber_printf(ber, "s{", logString); /* * Now we start adding the relocations. * Let's add the timestamp as the first one * so it's out of the field loop */ rc |= ber_printf(ber, "{i", ZOS_REMOTE_RELOC_TIMESTAMP); rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG); rc |= ber_printf(ber, "s}", timestamp); /* * Check that encoding is going OK until now */ if (rc < 0) goto skip_event; /* * Now go to first field, * and iterate through all fields */ auparse_first_field(au); do { /* * we set a maximum of 1024 chars for * relocation data (field=value pairs) * Hopefully this wont overflow too often */ char data[1024]; const char *name = auparse_get_field_name(au); const char *value = auparse_interpret_field(au); if (name == NULL || value == NULL) goto skip_event; /* * First reloc field is the Relocation type * We use 'OTHER' here since we don't have * anything better */ rc |= ber_printf(ber, "{i", ZOS_REMOTE_RELOC_OTHER); /* * Second field is the relocation data * We use a 'name=value' pair here * Use up to 1023 chars (one char left for '\0') */ snprintf(data, 1023, "%s=%s", name, value); rc |= ber_printf(ber, "t", ASN1_IA5STRING_TAG); rc |= ber_printf(ber, "s}", data); /* * Check encoding status */ if (rc < 0) goto skip_event; } while (auparse_next_field(au) > 0); /* * After adding all relocations we are done with * this item - finalize relocs and item */ rc |= ber_printf(ber, "}}"); /* * Check if we are doing well with encoding */ if (rc < 0) goto skip_event; } while (auparse_next_record(au) > 0); /* * We have all items in - finalize item sequence & request */ rc |= ber_printf(ber, "}}"); /* * Check if everything went alright with encoding */ if (rc < 0) goto skip_event; /* * finally, enqueue request and let the other * thread process it */ log_debug("Encoding done, enqueuing event"); enqueue(ber); return; skip_event: log_warn("Warning - error encoding request, skipping event"); ber_free(ber, 1); /* free it since we're not enqueuing it */ return; fatal: log_err("Error - Fatal error while encoding request. Aborting"); stop = 1; } int main(int argc, char *argv[]) { int rc; const char *cpath; char buf[1024]; struct sigaction sa; sigset_t ss; auparse_state_t *au; ssize_t len; mypid = getpid(); log_info("starting with pid=%d", mypid); /* * install signal handlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); sa.sa_handler = alarm_handler; sigaction(SIGALRM, &sa, NULL); /* * the main program accepts a single (optional) argument: * it's configuration file (this is NOT the plugin configuration * usually located at /etc/audit/plugins.d) * We use the default (def_config_file) if no arguments are given */ if (argc == 1) { cpath = def_config_file; log_warn("No configuration file specified - using default (%s)", cpath); } else if (argc == 2) { cpath = argv[1]; log_info("Using configuration file: %s", cpath); } else { log_err("Error - invalid number of parameters passed. Aborting"); return 1; } /* initialize record counter */ conf.counter = 1; /* initialize configuration with default values */ plugin_clear_config(&conf); /* initialize the submission queue */ if (init_queue(conf.q_depth) != 0) { log_err("Error - Can't initialize event queue. Aborting"); return -1; } #ifdef HAVE_LIBCAP_NG // Drop all capabilities capng_clear(CAPNG_SELECT_BOTH); if (capng_apply(CAPNG_SELECT_BOTH)) syslog(LOG_WARNING, "zos-remote plugin was unable to drop capabilities, continuing with elevated priviles"); #endif /* set stdin to O_NONBLOCK */ if (fcntl(0, F_SETFL, O_NONBLOCK) == -1) { log_err("Error - Can't set input to Non-blocking mode: %s. Aborting", strerror(errno)); return -1; } do { hup = 0; /* don't flush unless hup == 1 */ /* * initialization is done in 4 steps: */ /* * load configuration and * increase queue depth if needed */ rc = plugin_load_config(&conf, cpath); if (rc != 0) { log_err("Error - Can't load configuration. Aborting"); return -1; } increase_queue_depth(conf.q_depth); /* 1 */ /* initialize auparse */ au = auparse_init(AUSOURCE_FEED, 0); /* 2 */ if (au == NULL) { log_err("Error - exiting due to auparse init errors"); return -1; } /* * Block signals for everyone, * Initialize submission thread, and * Unblock signals for this thread */ sigfillset(&ss); pthread_sigmask(SIG_BLOCK, &ss, NULL); pthread_create(&submission_thread, NULL, submission_thread_main, NULL); pthread_sigmask(SIG_UNBLOCK, &ss, NULL); /* 3 */ /* add our event consumer callback */ auparse_add_callback(au, push_event, NULL, NULL); /* 4 */ /* main loop */ rc = 0; while (hup == 0 && stop == 0) { fd_set rfds; struct timeval tv; if (rc == 0 && auparse_feed_has_data(au)) auparse_feed_age_events(au); FD_ZERO(&rfds); FD_SET(0, &rfds); tv.tv_sec = 5; tv.tv_usec = 0; rc = select(1, &rfds, NULL, NULL, &tv); if (rc == -1) { if (errno == EINTR) { log_debug("Select call interrupted"); continue; } else { log_err("Error - Fatal error while monitoring input: %s. Aborting", strerror(errno)); stop = 1; } } else if (rc) { len = read(0, buf, 1024); if (len > 0) /* let our callback know of the new data */ auparse_feed(au, buf, len); else if (len == 0) { log_debug("End of input - Exiting"); stop = 1; } else { /* ignore interrupted call or empty pipe */ if (errno != EINTR && errno != EAGAIN) { log_err("Error - Fatal error while reading input: %s. Aborting", strerror(errno)); stop = 1; } else { log_debug("Ignoring read interruption: %s", strerror(errno)); } } } } /* flush everything, in order */ auparse_flush_feed(au); /* 4 */ alarm(10); /* 10 seconds to clear the queue */ pthread_join(submission_thread, NULL); /* 3 */ alarm(0); /* cancel any pending alarm */ auparse_destroy(au); /* 2 */ plugin_free_config(&conf); /* 1 */ } while (hup && stop == 0); /* destroy queue before leaving */ destroy_queue(); log_info("Exiting"); return 0; } audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote-queue.c000066400000000000000000000106201501761310600252610ustar00rootroot00000000000000/*************************************************************************** * Copyright (C) 2007 International Business Machines Corp. * * All Rights Reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * * * Authors: * * Klaus Heinrich Kiwi * * based on code by Steve Grubb * ***************************************************************************/ #include "zos-remote-queue.h" #include #include #include #ifndef HAVE_PTHREAD_YIELD #include #endif #include "zos-remote-log.h" static volatile BerElement **q; static pthread_mutex_t queue_lock; static pthread_cond_t queue_nonempty; static unsigned int q_next, q_last, q_depth; int init_queue(unsigned int size) { unsigned int i; q_next = 0; q_last = 0; q_depth = size; q = malloc(q_depth * sizeof(BerElement *)); if (q == NULL) return -1; for (i=0; i 3) { log_err("queue is full - dropping event"); return; } pthread_mutex_lock(&queue_lock); /* OK, have lock add event */ n = q_next%q_depth; if (q[n] == NULL) { q[n] = ber; q_next = (n+1) % q_depth; pthread_cond_signal(&queue_nonempty); pthread_mutex_unlock(&queue_lock); } else { pthread_mutex_unlock(&queue_lock); #ifdef HAVE_PTHREAD_YIELD pthread_yield(); /* Let dequeue thread run to clear queue */ #else sched_yield(); #endif retry_cnt++; goto retry; } } BerElement *dequeue(void) { BerElement *ber; unsigned int n; /* Wait until its got something in it */ pthread_mutex_lock(&queue_lock); n = q_last%q_depth; if (q[n] == NULL) { pthread_cond_wait(&queue_nonempty, &queue_lock); n = q_last%q_depth; } /* OK, grab the next event */ if (q[n] != NULL) { ber = (BerElement *) q[n]; q[n] = NULL; q_last = (n+1) % q_depth; } else ber = NULL; pthread_mutex_unlock(&queue_lock); /* Process the event */ return ber; } void nudge_queue(void) { pthread_cond_signal(&queue_nonempty); } void increase_queue_depth(unsigned int size) { pthread_mutex_lock(&queue_lock); if (size > q_depth) { unsigned int i; void *tmp_q; tmp_q = realloc(q, size * sizeof(BerElement *)); if (tmp_q == NULL) { log_err("Out of memory. Check %s file, %d line", __FILE__, __LINE__); pthread_mutex_unlock(&queue_lock); return; } q = tmp_q; for (i=q_depth; i * * based on code by Steve Grubb * ***************************************************************************/ #ifndef _ZOS_REMOTE_QUEUE_H #define _ZOS_REMOTE_QUEUE_H #include int init_queue(unsigned int size); void enqueue(BerElement *); BerElement *dequeue(void); void nudge_queue(void); void increase_queue_depth(unsigned int size); void destroy_queue(void); #endif /* _ZOS_REMOTE_QUEUE_H */ audit-userspace-4.0.5/audisp/plugins/zos-remote/zos-remote.conf000066400000000000000000000003661501761310600246500ustar00rootroot00000000000000## This is the configuration file for the audispd-zos-remote ## Audit dispatcher plugin. ## See zos-remote.conf(5) for more information server = zos_server.localdomain port = 389 user = RACF_ID password = racf_password timeout = 15 q_depth = 64 audit-userspace-4.0.5/audisp/queue.c000066400000000000000000000231671501761310600174040ustar00rootroot00000000000000/* queue.c -- * Copyright 2007,2013,2015,2018,2022 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include "queue.h" #include "common.h" /* * Audisp uses a simple ring buffer to pass events from auditd to its * plugin dispatcher thread. The goal is to avoid blocking producers * and consumers on a mutex. The semaphore below tracks how many events * are queued while the atomic indices maintain the next slot to use for * enqueueing and dequeueing. A mutex is only required when the queue is * resized. */ static volatile event_t **q; static pthread_mutex_t queue_lock; static sem_t queue_nonempty; #ifdef HAVE_ATOMIC /* * q_next points to the next free slot for the producer. * q_last points to the next item the consumer should read. * Both are updated atomically and wrap at q_depth. */ static atomic_uint q_next, q_last; extern ATOMIC_INT disp_hup; #else static unsigned int q_next, q_last; /* Fallback when atomics are absent */ extern volatile ATOMIC_INT disp_hup; #endif static unsigned int q_depth, processing_suspended, overflowed; static ATOMIC_UNSIGNED currently_used, max_used; static const char *SINGLE = "1"; static const char *HALT = "0"; static int queue_full_warning = 0; #define QUEUE_FULL_LIMIT 5 void reset_suspended(void) { processing_suspended = 0; queue_full_warning = 0; } int init_queue(unsigned int size) { // The global variables are initialized to zero by the // compiler. We can sometimes get here by a reconfigure. // If the queue was already initialized, q_depth will be // non-zero. In that case, leave everything alone. If the // queue was destroyed due to lack of plugins, q_depth, // as well as other queue variables, is set to zero so // they do not need reinitializing. if (q_depth == 0) { unsigned int i; q_depth = size; q = malloc(q_depth * sizeof(event_t *)); if (q == NULL) { processing_suspended = 1; return -1; } for (i=0; i < q_depth; i++) q[i] = NULL; /* Setup IPC mechanisms */ pthread_mutex_init(&queue_lock, NULL); sem_init(&queue_nonempty, 0, 0); #ifdef HAVE_ATOMIC atomic_init(&q_next, 0); atomic_init(&q_last, 0); #else q_next = 0; q_last = 0; #endif reset_suspended(); } return 0; } static void change_runlevel(const char *level) { char *argv[3]; int pid; static const char *init_pgm = "/sbin/init"; // In case of halt, we need to log the message before we halt if (strcmp(level, HALT) == 0) { write_to_console("audit: will try to change runlevel to %s\n", level); } pid = fork(); if (pid < 0) { syslog(LOG_ALERT, "Audispd failed to fork switching runlevels"); return; } if (pid) { /* Parent */ int status; // Wait until child exits if (waitpid(pid, &status, 0) < 0) { return; } // Check if child exited normally, runlevel change was successful if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { write_to_console("audit: changed runlevel to %s\n", level); } return; } /* Child */ argv[0] = (char *)init_pgm; argv[1] = (char *)level; argv[2] = NULL; execve(init_pgm, argv, NULL); syslog(LOG_ALERT, "Audispd failed to exec %s", init_pgm); exit(1); } static int do_overflow_action(struct disp_conf *config) { int rc = -1; overflowed = 1; switch (config->overflow_action) { case O_IGNORE: rc = 0; break; case O_SYSLOG: if (queue_full_warning < QUEUE_FULL_LIMIT) { syslog(LOG_ERR, "queue to plugins is full - dropping event"); queue_full_warning++; if (queue_full_warning == QUEUE_FULL_LIMIT) syslog(LOG_ERR, "auditd queue full reporting " "limit reached - ending " "dropped event notifications"); } break; case O_SUSPEND: syslog(LOG_ALERT, "Auditd is suspending event passing to plugins due to overflowing its queue."); processing_suspended = 1; break; case O_SINGLE: syslog(LOG_ALERT, "Auditd is now changing the system to single user mode due to overflowing its queue"); change_runlevel(SINGLE); break; case O_HALT: syslog(LOG_ALERT, "Auditd is now halting the system due to overflowing its queue"); change_runlevel(HALT); break; default: syslog(LOG_ALERT, "Unknown overflow action requested"); break; } return rc; } /* returns 0 on success and -1 on error */ int enqueue(event_t *e, struct disp_conf *config) { unsigned int n, retry_cnt = 0; if (processing_suspended) { free(e); return 0; } retry: /* We allow 3 retries and then its over */ if (retry_cnt > 3) { free(e); return do_overflow_action(config); } #ifdef HAVE_ATOMIC /* * Load the producer index with relaxed ordering. sem_post() acts * as a release barrier and sem_wait() in dequeue() provides the * matching acquire barrier. Because the threads synchronize on * the semaphore, a relaxed load of q_next is sufficient here. */ n = atomic_load_explicit(&q_next, memory_order_relaxed) % q_depth; #else n = q_next % q_depth; #endif if (q[n] == NULL) { q[n] = e; #ifdef HAVE_ATOMIC /* * Store the updated producer index with release semantics. * The event was written to q[n] above and sem_post() will be * issued next. sem_post() itself is a release barrier and * sem_wait() in dequeue() will acquire it, so the combination * guarantees the consumer sees the event before noticing that * q_next advanced. */ atomic_store_explicit(&q_next, (n+1) % q_depth, memory_order_release); #else q_next = (n+1) % q_depth; #endif currently_used++; if (currently_used > max_used) max_used = currently_used; sem_post(&queue_nonempty); } else { struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 2 * 1000 * 1000; /* 2 milliseconds */ nanosleep(&ts, NULL); /* Let other thread try to log it. */ retry_cnt++; goto retry; } return 0; } event_t *dequeue(void) { event_t *e; unsigned int n; /* Wait until there is something in the queue */ while (sem_wait(&queue_nonempty) == -1 && errno == EINTR) ; if (AUDIT_ATOMIC_LOAD(disp_hup)) return NULL; #ifdef HAVE_ATOMIC /* * The consumer waits on sem_wait() above which provides an acquire * barrier for the producer's sem_post(). Because of that * synchronization a relaxed load of the consumer index is safe here. */ n = atomic_load_explicit(&q_last, memory_order_relaxed) % q_depth; #else n = q_last % q_depth; #endif if (q[n] != NULL) { e = (event_t *)q[n]; q[n] = NULL; #ifdef HAVE_ATOMIC /* * Release ensures the slot is cleared before we advance the * consumer index. The following sem_post() pairs with the * producer's sem_wait(), so the semaphore again provides the * cross-thread ordering needed for the queue operations. */ atomic_store_explicit(&q_last, (n+1) % q_depth, memory_order_release); #else q_last = (n+1) % q_depth; #endif currently_used--; } else e = NULL; return e; } void nudge_queue(void) { sem_post(&queue_nonempty); } void increase_queue_depth(unsigned int size) { pthread_mutex_lock(&queue_lock); if (size > q_depth) { unsigned int i; void *tmp_q; tmp_q = realloc(q, size * sizeof(event_t *)); if (tmp_q == NULL) { fprintf(stderr, "Out of Memory. Check %s file, %d line", __FILE__, __LINE__); pthread_mutex_unlock(&queue_lock); return; } q = tmp_q; for (i=q_depth; i */ #ifndef QUEUE_HEADER #define QUEUE_HEADER #include #include "libdisp.h" #include "audispd-config.h" void reset_suspended(void); int init_queue(unsigned int size); int enqueue(event_t *e, struct disp_conf *config); event_t *dequeue(void); void nudge_queue(void); void increase_queue_depth(unsigned int size); void write_queue_state(FILE *f); void resume_queue(void); void destroy_queue(void); #endif audit-userspace-4.0.5/audit.spec000066400000000000000000000245361501761310600166120ustar00rootroot00000000000000Summary: User space tools for kernel auditing Name: audit Version: 4.0.5 Release: 1%{dist} License: GPL-2.0-or-later AND LGPL-2.0-or-later Group: System Environment/Daemons URL: https://github.com/linux-audit/audit-userspace/ Source0: https://github.com/linux-audit/audit-userspace/releases/tag/v%{version}.tar.gz BuildRequires: make gcc BuildRequires: kernel-headers >= 5.0 BuildRequires: systemd BuildRequires: autoconf automake libtool Requires: %{name}-libs = %{version}-%{release} Requires: %{name}-rules%{?_isa} = %{version}-%{release} Requires(post): systemd coreutils Requires(preun): systemd Requires(postun): systemd coreutils Recommends: initscripts-service %description The audit package contains the user space utilities for storing and searching the audit records generated by the audit subsystem in the Linux 2.6 and later kernels. %package libs Summary: Dynamic library for libaudit License: LGPL-2.0-or-later BuildRequires: libcap-ng-devel %description libs The audit-libs package contains the dynamic libraries needed for applications to use the audit framework. %package libs-devel Summary: Header files for libaudit License: LGPL-2.0-or-later Requires: %{name}-libs%{?_isa} = %{version}-%{release} Requires: kernel-headers >= 5.0 %description libs-devel The audit-libs-devel package contains the header files needed for developing applications that need to use the audit framework libraries. %package libs-static Summary: Static version of libaudit library License: LGPL-2.0-or-later Requires: kernel-headers >= 5.0 %description libs-static The audit-libs-static package contains the static libraries needed for developing applications that need to use static audit framework libraries %package -n python3-audit Summary: Python3 bindings for libaudit License: LGPL-2.0-or-later BuildRequires: python3-devel python-unversioned-command swig Requires: %{name}-libs%{?_isa} = %{version}-%{release} Provides: audit-libs-python3 = %{version}-%{release} %description -n python3-audit The audit-libs-python3 package contains the bindings so that libaudit and libauparse can be used by python3. %package -n audispd-plugins Summary: Plugins for the audit event dispatcher License: GPL-2.0-or-later BuildRequires: krb5-devel libcap-ng-devel Requires: %{name} = %{version}-%{release} Requires: %{name}-libs%{?_isa} = %{version}-%{release} %description -n audispd-plugins The audispd-plugins package provides plugins for the real-time interface to the audit system, audispd. These plugins can do things like relay events to remote machines or analyze events for suspicious behavior. %package -n audispd-plugins-zos Summary: z/OS plugin for the audit event dispatcher License: GPL-2.0-or-later BuildRequires: openldap-devel Requires: %{name}%{?_isa} = %{version}-%{release} Requires: %{name}-libs%{?_isa} = %{version}-%{release} %description -n audispd-plugins-zos The audispd-plugins-zos package provides a plugin that will forward all incoming audit events, as they happen, to a configured z/OS SMF (Service Management Facility) database, through an IBM Tivoli Directory Server (ITDS) set for Remote Audit service. %package rules Summary: audit rules and utilities License: GPL-2.0-or-later Recommends: %{name} = %{version}-%{release} %description rules The audit rules package contains the rules and utilities to load audit rules. %prep %setup -q -n %{name}-userspace-%{version} %build autoreconf -fv --install %configure --with-python3=yes --enable-gssapi-krb5=yes \ --with-arm --with-aarch64 --with-riscv --with-libcap-ng=yes \ --without-golang --enable-zos-remote \ --enable-experimental --with-io_uring make CFLAGS="%{optflags}" %{?_smp_mflags} %install mkdir -p $RPM_BUILD_ROOT/{sbin,etc/audit/plugins.d,etc/audit/rules.d} mkdir -p $RPM_BUILD_ROOT/%{_mandir}/{man5,man8} mkdir -p $RPM_BUILD_ROOT/%{_libdir}/audit mkdir --mode=0700 -p $RPM_BUILD_ROOT/%{_var}/log/audit mkdir -p $RPM_BUILD_ROOT/%{_var}/spool/audit make DESTDIR=$RPM_BUILD_ROOT install find $RPM_BUILD_ROOT -name '*.la' -delete find $RPM_BUILD_ROOT/%{_libdir}/python%{python3_version}/site-packages -name '*.a' -delete || true # On platforms with 32 & 64 bit libs, we need to coordinate the timestamp touch -r ./audit.spec $RPM_BUILD_ROOT/etc/libaudit.conf touch -r ./audit.spec $RPM_BUILD_ROOT/usr/share/man/man5/libaudit.conf.5.gz %check make %{?_smp_mflags} check # Get rid of make files so that they don't get packaged. rm -f rules/Makefile* %post %systemd_post auditd.service # If an upgrade, restart it if it's running if [ $1 -eq 2 ]; then state=$(systemctl show -P ActiveState auditd) if [ $state = "active" ] ; then auditctl --signal stop || true systemctl start auditd fi # if an install, start it since preset says we should be running elif [ $1 -eq 1 ]; then systemctl start auditd fi %post rules %systemd_post audit-rules.service # Copy default rules into place on new installation files=`ls /etc/audit/rules.d/ 2>/dev/null | wc -w` if [ "$files" -eq 0 ] ; then cp %{_datadir}/%{name}-rules/10-base-config.rules /etc/audit/rules.d/audit.rules # Fix up permissions chmod 0600 /etc/audit/rules.d/audit.rules # Make the new rules active augenrules --load fi %preun %systemd_preun auditd.service # If uninstalling, stop it if [ $1 -eq 0 ]; then auditctl --signal stop || true fi %preun rules %systemd_preun audit-rules.service # If uninstalling, delete the rules loaded in the kernel if [ $1 -eq 0 ]; then auditctl -D > /dev/null 2>&1 fi %files libs %license COPYING.LIB %{_libdir}/libaudit.so.1* %{_libdir}/libauparse.* %config(noreplace) %attr(640,root,root) /etc/libaudit.conf %{_mandir}/man5/libaudit.conf.5.gz %files libs-devel %doc contrib/plugin %{_libdir}/libaudit.so %{_libdir}/libauparse.so %{_includedir}/libaudit.h %{_includedir}/audit_logging.h %{_includedir}/audit-records.h %{_includedir}/auparse.h %{_includedir}/auparse-defs.h %{_datadir}/aclocal/audit.m4 %{_libdir}/pkgconfig/audit.pc %{_libdir}/pkgconfig/auparse.pc %{_mandir}/man3/* %attr(644,root,root) %{_mandir}/man5/ausearch-expression.5.gz %files libs-static %license COPYING.LIB %{_libdir}/libaudit.a %{_libdir}/libauparse.a %files -n python3-audit %defattr(-,root,root,-) %attr(755,root,root) %{python3_sitearch}/* %files %license COPYING %doc README.md ChangeLog rules init.d/auditd.cron %attr(644,root,root) %{_mandir}/man8/auditd.8.gz %attr(644,root,root) %{_mandir}/man8/aureport.8.gz %attr(644,root,root) %{_mandir}/man8/ausearch.8.gz %attr(644,root,root) %{_mandir}/man8/aulast.8.gz %attr(644,root,root) %{_mandir}/man8/aulastlog.8.gz %attr(644,root,root) %{_mandir}/man8/ausyscall.8.gz %attr(644,root,root) %{_mandir}/man5/auditd.conf.5.gz %attr(644,root,root) %{_mandir}/man5/auditd.cron.5.gz %attr(644,root,root) %{_mandir}/man5/auditd-plugins.5.gz %attr(755,root,root) %{_sbindir}/auditd %attr(755,root,root) %{_sbindir}/ausearch %attr(755,root,root) %{_sbindir}/aureport %attr(755,root,root) %{_bindir}/aulast %attr(755,root,root) %{_bindir}/aulastlog %attr(755,root,root) %{_bindir}/ausyscall %attr(640,root,root) %{_tmpfilesdir}/audit.conf %attr(644,root,root) %{_unitdir}/auditd.service %attr(750,root,root) %dir %{_libexecdir}/initscripts/legacy-actions/auditd %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/condrestart %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/reload %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/restart %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/resume %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/rotate %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/state %attr(750,root,root) %{_libexecdir}/initscripts/legacy-actions/auditd/stop %ghost %{_localstatedir}/run/auditd.state %attr(-,root,-) %dir %{_var}/log/audit %attr(750,root,root) %dir /etc/audit/plugins.d %config(noreplace) %attr(640,root,root) /etc/audit/auditd.conf %files rules %attr(755,root,root) %dir %{_datadir}/%{name}-rules %attr(644,root,root) %{_datadir}/%{name}-rules/* %attr(644,root,root) %{_mandir}/man8/auditctl.8.gz %attr(644,root,root) %{_mandir}/man8/augenrules.8.gz %attr(644,root,root) %{_mandir}/man7/audit.rules.7.gz %attr(755,root,root) %{_sbindir}/auditctl %attr(755,root,root) %{_sbindir}/augenrules %attr(644,root,root) %{_unitdir}/audit-rules.service %attr(750,root,root) %dir /etc/audit %attr(750,root,root) %dir /etc/audit/rules.d %ghost %config(noreplace) %attr(640,root,root) /etc/audit/rules.d/audit.rules %ghost %config(noreplace) %attr(640,root,root) /etc/audit/audit.rules %config(noreplace) %attr(640,root,root) /etc/audit/audit-stop.rules %files -n audispd-plugins %config(noreplace) %attr(640,root,root) /etc/audit/audisp-remote.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/au-remote.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/syslog.conf %config(noreplace) %attr(640,root,root) /etc/audit/audisp-statsd.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/au-statsd.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/af_unix.conf %config(noreplace) %attr(640,root,root) /etc/audit/ids.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/audisp-ids.conf %config(noreplace) %attr(640,root,root) /etc/audit/audisp-filter.conf %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/filter.conf %attr(644,root,root) %{_datadir}/%{name}-rules/ids-rules/* %attr(750,root,root) %{_sbindir}/audisp-remote %attr(750,root,root) %{_sbindir}/audisp-syslog %attr(750,root,root) %{_sbindir}/audisp-af_unix %attr(750,root,root) %{_sbindir}/audisp-ids %attr(750,root,root) %{_sbindir}/audisp-statsd %attr(750,root,root) %{_sbindir}/audisp-filter %attr(700,root,root) %dir %{_var}/spool/audit %attr(644,root,root) %{_mandir}/man5/audisp-remote.conf.5.gz %attr(644,root,root) %{_mandir}/man8/audisp-remote.8.gz %attr(644,root,root) %{_mandir}/man8/audisp-syslog.8.gz %attr(644,root,root) %{_mandir}/man8/audisp-af_unix.8.gz %attr(644,root,root) %{_mandir}/man8/audisp-statsd.8.gz %attr(644,root,root) %{_mandir}/man8/audisp-filter.8.gz %files -n audispd-plugins-zos %attr(644,root,root) %{_mandir}/man8/audispd-zos-remote.8.gz %attr(644,root,root) %{_mandir}/man5/zos-remote.conf.5.gz %config(noreplace) %attr(640,root,root) /etc/audit/plugins.d/audispd-zos-remote.conf %config(noreplace) %attr(640,root,root) /etc/audit/zos-remote.conf %attr(750,root,root) %{_sbindir}/audispd-zos-remote %changelog Tue Jun 03 2025 Steve Grubb 4.0.5-1 - New upstream release audit-userspace-4.0.5/auparse/000077500000000000000000000000001501761310600162565ustar00rootroot00000000000000audit-userspace-4.0.5/auparse/Makefile.am000066400000000000000000001076771501761310600203340ustar00rootroot00000000000000# Makefile.am -- # Copyright 2006-08,2011-18,2024-25 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # Richard Guy Briggs # SUBDIRS = test EXTRA_DIST = expression-design.txt CLEANFILES = $(BUILT_SOURCES) CONFIG_CLEAN_FILES = *.loT *.rej *.orig AM_CFLAGS = -fPIC -DPIC -D_GNU_SOURCE -g ${DEBUG} -Wno-pointer-sign -Wno-enum-compare -Wno-switch ${WFLAGS} AM_CPPFLAGS = -I. -I${top_srcdir} -I${top_srcdir}/src -I${top_srcdir}/lib -I${top_srcdir}/common LIBS = pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = auparse.pc DISTCLEANFILES = $(pkgconfig_DATA) lib_LTLIBRARIES = libauparse.la include_HEADERS = auparse.h auparse-defs.h libauparse_la_SOURCES = lru.c interpret.c nvlist.c ellist.c \ auparse.c auditd-config.c message.c data_buf.c \ auparse-defs.h auparse-idata.h data_buf.h \ nvlist.h auparse.h ellist.h \ internal.h lru.h rnode.h interpret.h \ private.h expression.c expression.h tty_named_keys.h \ normalize.c normalize-llist.c normalize-llist.h \ normalize-internal.h normalize_obj_kind_map.h \ normalize_record_map.h normalize_syscall_map.h nodist_libauparse_la_SOURCES = $(BUILT_SOURCES) libauparse_la_LIBADD = ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la libauparse_la_DEPENDENCIES = $(libauparse_la_SOURCES) ${top_builddir}/config.h ${top_builddir}/common/libaucommon.la libauparse_la_LDFLAGS = -Wl,-z,relro message.c: cp ${top_srcdir}/lib/message.c . BUILT_SOURCES = accesstabs.h captabs.h clocktabs.h clone-flagtabs.h \ epoll_ctls.h famtabs.h fcntl-cmdtabs.h fsconfigs.h \ icmptypetabs.h ipctabs.h ipccmdtabs.h\ ioctlreqtabs.h ipoptnametabs.h ip6optnametabs.h \ mmaptabs.h mounttabs.h nfprototabs.h open-flagtabs.h \ persontabs.h prctl_opttabs.h pktoptnametabs.h \ prottabs.h ptracetabs.h \ rlimittabs.h recvtabs.h schedtabs.h seccomptabs.h \ seektabs.h shm_modetabs.h signaltabs.h sockoptnametabs.h \ socktabs.h sockleveltabs.h socktypetabs.h \ tcpoptnametabs.h typetabs.h umounttabs.h inethooktabs.h \ netactiontabs.h \ normalize_obj_kind_maps.h normalize_record_maps.h \ normalize_syscall_maps.h normalize_evtypetabs.h bpftabs.h \ openat2-resolvetabs.h xattr-atflagtabs.h access-flagtabs.h noinst_PROGRAMS = gen_accesstabs_h gen_captabs_h gen_clock_h \ gen_clone-flagtabs_h \ gen_epoll_ctls_h gen_famtabs_h gen_fcntl-cmdtabs_h \ gen_fsconfigs_h gen_ioctlreqtabs_h \ gen_icmptypetabs_h gen_ipctabs_h gen_ipccmdtabs_h\ gen_ipoptnametabs_h gen_ip6optnametabs_h gen_nfprototabs_h \ gen_mmaptabs_h gen_mounttabs_h \ gen_open-flagtabs_h gen_persontabs_h \ gen_prctl_opttabs_h gen_pktoptnametabs_h gen_prottabs_h \ gen_recvtabs_h gen_rlimit_h gen_ptracetabs_h \ gen_schedtabs_h gen_seccomptabs_h \ gen_seektabs_h gen_shm_modetabs_h gen_signals_h \ gen_sockoptnametabs_h gen_socktabs_h gen_sockleveltabs_h \ gen_socktypetabs_h gen_tcpoptnametabs_h gen_typetabs_h \ gen_umounttabs_h gen_inethooktabs_h gen_netactiontabs_h \ gen_normalize_record_map gen_normalize_syscall_map \ gen_normalize_obj_kind_map gen_normalize_evtypetabs_h gen_bpftabs_h \ gen_openat2-resolvetabs_h gen_xattr-atflagtabs_h gen_access-flagtabs_h gen_accesstabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h accesstab.h gen_accesstabs_h_CFLAGS = '-DTABLE_H="accesstab.h"' $(gen_accesstabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_accesstabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_accesstabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_accesstabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_accesstabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_accesstabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_accesstabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_accesstabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) accesstabs.h: gen_accesstabs_h Makefile ./gen_accesstabs_h --i2s-transtab access > $@ gen_access_flagtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h \ access-flagtab.h gen_access_flagtabs_h_CFLAGS = '-DTABLE_H="access-flagtab.h"' $(gen_access_flagtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_access_flagtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_access_flagtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_access_flagtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_access-flagtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_access-flagtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_access-flagtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_access-flagtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) access-flagtabs.h: gen_access-flagtabs_h Makefile ./gen_access-flagtabs_h --i2s-transtab access_flag > $@ gen_captabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h captab.h gen_captabs_h_CFLAGS = '-DTABLE_H="captab.h"' $(gen_captabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_captabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_captabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_captabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_captabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_captabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_captabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_captabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) captabs.h: gen_captabs_h Makefile ./gen_captabs_h --i2s cap > $@ gen_clock_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h clocktab.h gen_clock_h_CFLAGS = '-DTABLE_H="clocktab.h"' $(gen_clock_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_clock_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_clock_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_clock_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_clock_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_clock_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_clock_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_clock_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) clocktabs.h: gen_clock_h Makefile ./gen_clock_h --i2s clock > $@ gen_clone_flagtabs_h_SOURCES = ../lib/gen_tables64.c ../lib/gen_tables64.h \ clone-flagtab.h gen_clone_flagtabs_h_CFLAGS = '-DTABLE_H="clone-flagtab.h"' $(gen_clone_flagtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_clone_flagtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_clone_flagtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_clone_flagtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_clone-flagtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_clone-flagtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_clone-flagtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_clone-flagtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) clone-flagtabs.h: gen_clone-flagtabs_h Makefile ./gen_clone-flagtabs_h --64bit --i2s-transtab clone_flag > $@ gen_epoll_ctls_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h epoll_ctl.h gen_epoll_ctls_h_CFLAGS = '-DTABLE_H="epoll_ctl.h"' $(gen_epoll_ctls_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_epoll_ctls_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_epoll_ctls_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_epoll_ctls_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_epoll_ctls_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_epoll_ctls_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_epoll_ctls_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_epoll_ctls_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) epoll_ctls.h: gen_epoll_ctls_h Makefile ./gen_epoll_ctls_h --i2s epoll_ctl > $@ gen_famtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h famtab.h gen_famtabs_h_CFLAGS = '-DTABLE_H="famtab.h"' $(gen_famtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_famtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_famtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_famtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_famtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_famtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_famtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_famtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) famtabs.h: gen_famtabs_h Makefile ./gen_famtabs_h --i2s fam > $@ gen_fcntl_cmdtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h \ fcntl-cmdtab.h gen_fcntl_cmdtabs_h_CFLAGS = '-DTABLE_H="fcntl-cmdtab.h"' $(gen_fcntl_cmdtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_fcntl_cmdtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_fcntl_cmdtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_fcntl_cmdtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_fcntl-cmdtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_fcntl-cmdtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_fcntl-cmdtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_fcntl-cmdtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) fcntl-cmdtabs.h: gen_fcntl-cmdtabs_h Makefile ./gen_fcntl-cmdtabs_h --i2s fcntl > $@ gen_fsconfigs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h fsconfig.h gen_fsconfigs_h_CFLAGS = '-DTABLE_H="fsconfig.h"' $(gen_fsconfigs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_fsconfigs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_fsconfigs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_fsconfigs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_fsconfigs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_fsconfigs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_fsconfigs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_fsconfigs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) fsconfigs.h: gen_fsconfigs_h Makefile ./gen_fsconfigs_h --i2s fsconfig > $@ gen_icmptypetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h icmptypetab.h gen_icmptypetabs_h_CFLAGS = '-DTABLE_H="icmptypetab.h"' $(gen_icmptypetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_icmptypetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_icmptypetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_icmptypetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_icmptypetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_icmptypetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_icmptypetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_icmptypetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) icmptypetabs.h: gen_icmptypetabs_h Makefile ./gen_icmptypetabs_h --i2s icmptype > $@ gen_ioctlreqtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ioctlreqtab.h gen_ioctlreqtabs_h_CFLAGS = '-DTABLE_H="ioctlreqtab.h"' $(gen_ioctlreqtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ioctlreqtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ioctlreqtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ioctlreqtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ioctlreqtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ioctlreqtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ioctlreqtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ioctlreqtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ioctlreqtabs.h: gen_ioctlreqtabs_h Makefile ./gen_ioctlreqtabs_h --i2s ioctlreq > $@ gen_ipctabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ipctab.h gen_ipctabs_h_CFLAGS = '-DTABLE_H="ipctab.h"' $(gen_ipctabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ipctabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ipctabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ipctabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ipctabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ipctabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ipctabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ipctabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ipctabs.h: gen_ipctabs_h Makefile ./gen_ipctabs_h --i2s ipc > $@ gen_ipccmdtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ipccmdtab.h gen_ipccmdtabs_h_CFLAGS = '-DTABLE_H="ipccmdtab.h"' $(gen_ipccmdtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ipccmdtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ipccmdtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ipccmdtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ipccmdtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ipccmdtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ipccmdtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ipccmdtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ipccmdtabs.h: gen_ipccmdtabs_h Makefile ./gen_ipccmdtabs_h --i2s-transtab ipccmd > $@ gen_ipoptnametabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ipoptnametab.h gen_ipoptnametabs_h_CFLAGS = '-DTABLE_H="ipoptnametab.h"' $(gen_ipoptnametabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ipoptnametabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ipoptnametabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ipoptnametabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ipoptnametabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ipoptnametabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ipoptnametabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ipoptnametabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ipoptnametabs.h: gen_ipoptnametabs_h Makefile ./gen_ipoptnametabs_h --i2s ipoptname > $@ gen_ip6optnametabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ip6optnametab.h gen_ip6optnametabs_h_CFLAGS = '-DTABLE_H="ip6optnametab.h"' $(gen_ip6optnametabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ip6optnametabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ip6optnametabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ip6optnametabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ip6optnametabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ip6optnametabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ip6optnametabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ip6optnametabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ip6optnametabs.h: gen_ip6optnametabs_h Makefile ./gen_ip6optnametabs_h --i2s ip6optname > $@ gen_mmaptabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h mmaptab.h gen_mmaptabs_h_CFLAGS = '-DTABLE_H="mmaptab.h"' $(gen_mmaptabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_mmaptabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_mmaptabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_mmaptabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_mmaptabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_mmaptabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_mmaptabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_mmaptabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) mmaptabs.h: gen_mmaptabs_h Makefile ./gen_mmaptabs_h --i2s-transtab mmap > $@ gen_mounttabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h mounttab.h gen_mounttabs_h_CFLAGS = '-DTABLE_H="mounttab.h"' $(gen_mounttabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_mounttabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_mounttabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_mounttabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_mounttabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_mounttabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_mounttabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_mounttabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) mounttabs.h: gen_mounttabs_h Makefile ./gen_mounttabs_h --i2s-transtab mount > $@ gen_nfprototabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h nfprototab.h gen_nfprototabs_h_CFLAGS = '-DTABLE_H="nfprototab.h"' $(gen_nfprototabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_nfprototabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_nfprototabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_nfprototabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_nfprototabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_nfprototabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_nfprototabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_nfprototabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) nfprototabs.h: gen_nfprototabs_h Makefile ./gen_nfprototabs_h --i2s nfproto > $@ gen_open_flagtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h \ open-flagtab.h gen_open_flagtabs_h_CFLAGS = '-DTABLE_H="open-flagtab.h"' $(gen_open_flagtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_open_flagtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_open_flagtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_open_flagtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_open-flagtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_open-flagtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_open-flagtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_open-flagtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) open-flagtabs.h: gen_open-flagtabs_h Makefile ./gen_open-flagtabs_h --i2s-transtab open_flag > $@ gen_xattr_atflagtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h \ xattr-atflagtab.h gen_xattr_atflagtabs_h_CFLAGS = '-DTABLE_H="xattr-atflagtab.h"' $(gen_xattr_atflagtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_xattr_atflagtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_xattr_atflagtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_xattr_atflagtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_xattr-atflagtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_xattr-atflagtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_xattr-atflagtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_xattr-atflagtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) xattr-atflagtabs.h: gen_xattr-atflagtabs_h Makefile ./gen_xattr-atflagtabs_h --i2s-transtab xattr_atflag > $@ gen_persontabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h persontab.h gen_persontabs_h_CFLAGS = '-DTABLE_H="persontab.h"' $(gen_persontabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_persontabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_persontabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_persontabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_persontabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_persontabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_persontabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_persontabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) persontabs.h: gen_persontabs_h Makefile ./gen_persontabs_h --i2s person > $@ gen_ptracetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h ptracetab.h gen_ptracetabs_h_CFLAGS = '-DTABLE_H="ptracetab.h"' $(gen_ptracetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ptracetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ptracetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ptracetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ptracetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ptracetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ptracetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ptracetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ptracetabs.h: gen_ptracetabs_h Makefile ./gen_ptracetabs_h --i2s ptrace > $@ gen_prctl_opttabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h prctl-opt-tab.h gen_prctl_opttabs_h_CFLAGS = '-DTABLE_H="prctl-opt-tab.h"' $(gen_prctl_opttabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_prctl_opttabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_prctl_opttabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_prctl_opttabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_prctl_opttabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_prctl_opttabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_prctl_opttabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_prctl_opttabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) prctl_opttabs.h: gen_prctl_opttabs_h Makefile ./gen_prctl_opttabs_h --i2s prctl_opt > $@ gen_pktoptnametabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h pktoptnametab.h gen_pktoptnametabs_h_CFLAGS = '-DTABLE_H="pktoptnametab.h"' $(gen_pktoptnametabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_pktoptnametabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_pktoptnametabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_pktoptnametabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_pktoptnametabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_pktoptnametabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_pktoptnametabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_pktoptnametabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) pktoptnametabs.h: gen_pktoptnametabs_h Makefile ./gen_pktoptnametabs_h --i2s pktoptname > $@ gen_prottabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h prottab.h gen_prottabs_h_CFLAGS = '-DTABLE_H="prottab.h"' $(gen_prottabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_prottabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_prottabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_prottabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_prottabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_prottabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_prottabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_prottabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) prottabs.h: gen_prottabs_h Makefile ./gen_prottabs_h --i2s-transtab prot > $@ gen_recvtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h recvtab.h gen_recvtabs_h_CFLAGS = '-DTABLE_H="recvtab.h"' $(gen_recvtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_recvtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_recvtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_recvtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_recvtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_recvtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_recvtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_recvtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) recvtabs.h: gen_recvtabs_h Makefile ./gen_recvtabs_h --i2s-transtab recv > $@ gen_rlimit_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h rlimittab.h gen_rlimit_h_CFLAGS = '-DTABLE_H="rlimittab.h"' $(gen_rlimit_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_rlimit_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_rlimit_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_rlimit_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_rlimit_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_rlimit_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_rlimit_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_rlimit_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) rlimittabs.h: gen_rlimit_h Makefile ./gen_rlimit_h --i2s rlimit > $@ gen_schedtabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h schedtab.h gen_schedtabs_h_CFLAGS = '-DTABLE_H="schedtab.h"' $(gen_schedtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_schedtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_schedtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_schedtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_schedtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_schedtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_schedtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_schedtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) schedtabs.h: gen_schedtabs_h Makefile ./gen_schedtabs_h --i2s sched > $@ gen_seccomptabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h seccomptab.h gen_seccomptabs_h_CFLAGS = '-DTABLE_H="seccomptab.h"' $(gen_seccomptabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_seccomptabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_seccomptabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_seccomptabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_seccomptabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_seccomptabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_seccomptabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_seccomptabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) seccomptabs.h: gen_seccomptabs_h Makefile ./gen_seccomptabs_h --i2s seccomp > $@ gen_seektabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h seektab.h gen_seektabs_h_CFLAGS = '-DTABLE_H="seektab.h"' $(gen_seektabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_seektabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_seektabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_seektabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_seektabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_seektabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_seektabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_seektabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) seektabs.h: gen_seektabs_h Makefile ./gen_seektabs_h --i2s seek > $@ gen_shm_modetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h shm_modetab.h gen_shm_modetabs_h_CFLAGS = '-DTABLE_H="shm_modetab.h"' $(gen_shm_modetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_shm_modetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_shm_modetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_shm_modetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_shm_modetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_shm_modetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_shm_modetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_shm_modetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) shm_modetabs.h: gen_shm_modetabs_h Makefile ./gen_shm_modetabs_h --i2s-transtab shm_mode > $@ gen_signals_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h signaltab.h gen_signals_h_CFLAGS = '-DTABLE_H="signaltab.h"' $(gen_signals_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_signals_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_signals_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_signals_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_signals_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_signals_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_signals_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_signals_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) signaltabs.h: gen_signals_h Makefile ./gen_signals_h --i2s signal > $@ gen_sockleveltabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h sockleveltab.h gen_sockleveltabs_h_CFLAGS = '-DTABLE_H="sockleveltab.h"' $(gen_sockleveltabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_sockleveltabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_sockleveltabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_sockleveltabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_sockleveltabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_sockleveltabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_sockleveltabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_sockleveltabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) sockleveltabs.h: gen_sockleveltabs_h Makefile ./gen_sockleveltabs_h --i2s socklevel > $@ gen_sockoptnametabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h sockoptnametab.h gen_sockoptnametabs_h_CFLAGS = '-DTABLE_H="sockoptnametab.h"' $(gen_sockoptnametabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_sockoptnametabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_sockoptnametabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_sockoptnametabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_sockoptnametabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_sockoptnametabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_sockoptnametabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_sockoptnametabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) sockoptnametabs.h: gen_sockoptnametabs_h Makefile ./gen_sockoptnametabs_h --i2s sockoptname > $@ gen_socktabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h socktab.h gen_socktabs_h_CFLAGS = '-DTABLE_H="socktab.h"' $(gen_socktabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_socktabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_socktabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_socktabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_socktabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_socktabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_socktabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_socktabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) socktabs.h: gen_socktabs_h Makefile ./gen_socktabs_h --i2s sock > $@ gen_socktypetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h socktypetab.h gen_socktypetabs_h_CFLAGS = '-DTABLE_H="socktypetab.h"' $(gen_socktypetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_socktypetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_socktypetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_socktypetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_socktypetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_socktypetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_socktypetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_socktypetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) socktypetabs.h: gen_socktypetabs_h Makefile ./gen_socktypetabs_h --i2s sock_type > $@ gen_tcpoptnametabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h tcpoptnametab.h gen_tcpoptnametabs_h_CFLAGS = '-DTABLE_H="tcpoptnametab.h"' $(gen_tcpoptnametabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_tcpoptnametabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_tcpoptnametabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_tcpoptnametabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_tcpoptnametabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_tcpoptnametabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_tcpoptnametabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_tcpoptnametabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) tcpoptnametabs.h: gen_tcpoptnametabs_h Makefile ./gen_tcpoptnametabs_h --i2s tcpoptname > $@ gen_typetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h typetab.h gen_typetabs_h_CFLAGS = '-DTABLE_H="typetab.h"' $(gen_typetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_typetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_typetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_typetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_typetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_typetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_typetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_typetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) typetabs.h: gen_typetabs_h Makefile ./gen_typetabs_h --s2i type > $@ gen_umounttabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h umounttab.h gen_umounttabs_h_CFLAGS = '-DTABLE_H="umounttab.h"' $(gen_umounttabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_umounttabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_umounttabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_umounttabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_umounttabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_umounttabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_umounttabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_umounttabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) umounttabs.h: gen_umounttabs_h Makefile ./gen_umounttabs_h --i2s-transtab umount > $@ gen_inethooktabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h inethooktab.h gen_inethooktabs_h_CFLAGS = '-DTABLE_H="inethooktab.h"' $(gen_inethooktabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_inethooktabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_inethooktabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_inethooktabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_inethooktabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_inethooktabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_inethooktabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_inethooktabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) inethooktabs.h: gen_inethooktabs_h Makefile ./gen_inethooktabs_h --i2s inethook > $@ gen_netactiontabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h netactiontab.h gen_netactiontabs_h_CFLAGS = '-DTABLE_H="netactiontab.h"' $(gen_netactiontabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_netactiontabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_netactiontabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_netactiontabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_netactiontabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_netactiontabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_netactiontabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_netactiontabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) netactiontabs.h: gen_netactiontabs_h Makefile ./gen_netactiontabs_h --i2s netaction > $@ gen_normalize_record_map_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h normalize_record_map.h gen_normalize_record_map_CFLAGS = '-DTABLE_H="normalize_record_map.h"' $(gen_normalize_record_map_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_normalize_record_map_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_normalize_record_map_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_normalize_record_map_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_normalize_record_map$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_normalize_record_map$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_normalize_record_map$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_normalize_record_map$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) normalize_record_maps.h: gen_normalize_record_map Makefile ./gen_normalize_record_map --lowercase --i2s normalize_record_map > $@ gen_normalize_syscall_map_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h normalize_syscall_map.h gen_normalize_syscall_map_CFLAGS = '-DTABLE_H="normalize_syscall_map.h"' $(gen_normalize_syscall_map_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_normalize_syscall_map_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_normalize_syscall_map_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_normalize_syscall_map_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_normalize_syscall_map$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_normalize_syscall_map$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_normalize_syscall_map$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_normalize_syscall_map$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) normalize_syscall_maps.h: gen_normalize_syscall_map Makefile ./gen_normalize_syscall_map --lowercase --s2i normalize_syscall_map > $@ gen_normalize_obj_kind_map_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h normalize_obj_kind_map.h gen_normalize_obj_kind_map_CFLAGS = '-DTABLE_H="normalize_obj_kind_map.h"' $(gen_normalize_obj_kind_map_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_normalize_obj_kind_map_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_normalize_obj_kind_map_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_normalize_obj_kind_map_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_normalize_obj_kind_map$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_normalize_obj_kind_map$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_normalize_obj_kind_map$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_normalize_obj_kind_map$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) normalize_obj_kind_maps.h: gen_normalize_obj_kind_map Makefile ./gen_normalize_obj_kind_map --lowercase --i2s normalize_obj_kind_map > $@ gen_normalize_evtypetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h normalize_evtypetab.h gen_normalize_evtypetabs_h_CFLAGS = '-DTABLE_H="normalize_evtypetab.h"' $(gen_normalize_evtypetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_normalize_evtypetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_normalize_evtypetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_normalize_evtypetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_normalize_evtypetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_normalize_evtypetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_normalize_evtypetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_normalize_evtypetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) normalize_evtypetabs.h: gen_normalize_evtypetabs_h Makefile ./gen_normalize_evtypetabs_h --i2s evtype > $@ gen_bpftabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h bpftab.h gen_bpftabs_h_CFLAGS = '-DTABLE_H="bpftab.h"' $(gen_bpftabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_bpftabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_bpftabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_bpftabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_bpftabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_bpftabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_bpftabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_bpftabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) bpftabs.h: gen_bpftabs_h Makefile ./gen_bpftabs_h --i2s bpf > $@ gen_openat2_resolvetabs_h_SOURCES = ../lib/gen_tables.c ../lib/gen_tables.h \ openat2-resolvetab.h gen_openat2_resolvetabs_h_CFLAGS = '-DTABLE_H="openat2-resolvetab.h"' $(gen_openat2_resolvetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_openat2_resolvetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_openat2_resolvetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_openat2_resolvetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_openat2-resolvetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_openat2-resolvetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_openat2-resolvetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_openat2-resolvetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) openat2-resolvetabs.h: gen_openat2-resolvetabs_h Makefile ./gen_openat2-resolvetabs_h --i2s-transtab openat2_resolve > $@ audit-userspace-4.0.5/auparse/access-flagtab.h000066400000000000000000000017421501761310600212720ustar00rootroot00000000000000/* access-modetab.h -- * Copyright Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Attila Lakatos * Location: fcntl.h */ _S(0x100, "AT_SYMLINK_NOFOLLOW" ) _S(0x200, "AT_EACCESS" ) _S(0x1000, "AT_EMPTY_PATH" ) audit-userspace-4.0.5/auparse/accesstab.h000066400000000000000000000017611501761310600203640ustar00rootroot00000000000000/* accesstab.h -- * Copyright 2013 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: ? */ // _S(0x0U, "F_OK" ) handled in interpret _S(0x1U, "X_OK" ) _S(0x2U, "W_OK" ) _S(0x4U, "R_OK" ) audit-userspace-4.0.5/auparse/auditd-config.c000066400000000000000000000206531501761310600211450ustar00rootroot00000000000000/* * auditd-config.c - This is a greatly reduced config file parser * * Copyright 2007,2014,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include "internal.h" #include #include #include #include #include #include #include #include #include "common.h" /* Local prototypes */ struct _pair { const char *name; const char *value; }; struct kw_pair { const char *name; int (*parser)(auparse_state_t *, const char *, int, struct daemon_conf *); }; struct nv_list { const char *name; int option; }; static char *get_line(auparse_state_t *au, FILE *f, char *buf, unsigned size, int *lineno, const char *file); static int nv_split(char *buf, struct _pair *nv); static const struct kw_pair *kw_lookup(const char *val); static int log_file_parser(auparse_state_t *au, const char *val, int line, struct daemon_conf *config); static int eoe_timeout_parser(auparse_state_t *au, const char *val, int line, struct daemon_conf *config); static const struct kw_pair keywords[] = { {"log_file", log_file_parser }, {"end_of_event_timeout", eoe_timeout_parser }, { NULL, NULL } }; /* * Set everything to its default value */ static void aup_clear_config(struct daemon_conf *config) { config->local_events = 1; config->sender_uid = 0; config->sender_pid = 0; config->sender_ctx = NULL; config->write_logs = 1; config->log_file = strdup("/var/log/audit/audit.log"); config->log_format = LF_RAW; config->log_group = 0; config->priority_boost = 4; config->flush = FT_NONE; config->freq = 0; config->num_logs = 0L; config->node_name_format = N_NONE; config->node_name = NULL; config->max_log_size = 0L; config->max_log_size_action = SZ_IGNORE; config->space_left = 0L; config->space_left_action = FA_IGNORE; config->space_left_exe = NULL; config->action_mail_acct = NULL; config->admin_space_left= 0L; config->admin_space_left_action = FA_IGNORE; config->admin_space_left_exe = NULL; config->disk_full_action = FA_IGNORE; config->disk_full_exe = NULL; config->disk_error_action = FA_SYSLOG; config->disk_error_exe = NULL; config->end_of_event_timeout = EOE_TIMEOUT; } int aup_load_config(auparse_state_t *au, struct daemon_conf *config, log_test_t lt __attribute__((unused))) { int fd, lineno = 1; FILE *f; char buf[160]; aup_clear_config(config); /* open the file */ fd = open(CONFIG_FILE, O_RDONLY|O_NOFOLLOW); if (fd < 0) { if (errno != ENOENT) { if (errno == EACCES) { audit_msg(au, LOG_INFO, "libauparse: Permission denied opening config file, using defaults"); return 0; } audit_msg(au, LOG_ERR, "Error opening config file (%s)", strerror(errno)); return 1; } audit_msg(au, LOG_WARNING, "Config file %s doesn't exist, skipping", CONFIG_FILE); return 0; } /* Make into FILE struct and read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { audit_msg(au, LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(au, f, buf, sizeof(buf), &lineno, CONFIG_FILE)) { // convert line into name-value pair const struct kw_pair *kw; struct _pair nv; int rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. audit_msg(au, LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, CONFIG_FILE); break; case 2: // no '=' sign audit_msg(au, LOG_ERR, "Missing equal sign for line %d in %s", lineno, CONFIG_FILE); break; default: // something else went wrong... audit_msg(au, LOG_ERR, "Unknown error for line %d in %s", lineno, CONFIG_FILE); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); audit_msg(au, LOG_ERR, "Not processing any more lines in %s", CONFIG_FILE); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name) { /* dispatch to keyword's local parser */ rc = kw->parser(au, nv.value, lineno, config); if (rc != 0) { fclose(f); return 1; // local parser puts message out } } lineno++; } fclose(f); return 0; } static char *get_line(auparse_state_t *au, FILE *f, char *buf, unsigned size, int *lineno, const char *file) { int too_long = 0; while (fgets_unlocked(buf, size, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) { if (!too_long) { *ptr = 0; return buf; } // Reset and start with the next line too_long = 0; *lineno = *lineno + 1; } else { // If a line is too long skip it. // Only output 1 warning if (!too_long) audit_msg(au, LOG_ERR, "Skipping line %d in %s: too long", *lineno, file); too_long = 1; } } return NULL; } static int nv_split(char *buf, struct _pair *nv) { /* Get the name part */ char *ptr; nv->name = NULL; nv->value = NULL; ptr = audit_strsplit(buf); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; nv->value = ptr; /* Make sure there's nothing else */ ptr = audit_strsplit(NULL); if (ptr) { /* Allow one option, but check that there's not 2 */ ptr = audit_strsplit(NULL); if (ptr) return 1; } /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int log_file_parser(auparse_state_t *au, const char *val, int line, struct daemon_conf *config) { char *dir = NULL, *tdir, *base; DIR *d; int fd, mode; /* split name into dir and basename. */ tdir = strdup(val); if (tdir) dir = dirname(tdir); if (dir == NULL || strlen(dir) < 4) { // '/var' is shortest dirname audit_msg(au, LOG_ERR, "The directory name: %s is too short - line %d", dir, line); free((void *)tdir); return 1; } base = basename((char *)val); if (base == 0 || strlen(base) == 0) { audit_msg(au, LOG_ERR, "The file name: %s is too short - line %d", base, line); free((void *)tdir); return 1; } /* verify the directory path exists */ d = opendir(dir); if (d == NULL) { audit_msg(au, LOG_ERR, "Could not open dir %s (%s)", dir, strerror(errno)); free((void *)tdir); return 1; } free((void *)tdir); closedir(d); /* Verify the log file can be opened. */ mode = O_RDONLY; fd = open(val, mode); if (fd < 0) { audit_msg(au, LOG_ERR, "Unable to open %s (%s)", val, strerror(errno)); return 1; } close(fd); free((void *)config->log_file); config->log_file = strdup(val); if (config->log_file == NULL) return 1; return 0; } static int eoe_timeout_parser(auparse_state_t *au, const char *val, int line, struct daemon_conf *config) { const char *ptr = val; unsigned long i; /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(au, LOG_ERR, "Value %s should only be numbers - line %d", val, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(val, NULL, 10); if (errno) { audit_msg(au, LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } config->end_of_event_timeout = i; return 0; } void aup_free_config(struct daemon_conf *config) { free((void*)config->log_file); config->log_file = NULL; } audit-userspace-4.0.5/auparse/auparse-defs.h000066400000000000000000000077271501761310600210230ustar00rootroot00000000000000/* auparse-defs.h -- * Copyright 2006-07,09,2011-12,2014-17,2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef AUPARSE_DEFS_HEADER #define AUPARSE_DEFS_HEADER #include #ifdef __cplusplus extern "C" { #endif /* Library type definitions */ /* This tells the library where the data source is located */ typedef enum { AUSOURCE_LOGS, AUSOURCE_FILE, AUSOURCE_FILE_ARRAY, AUSOURCE_BUFFER, AUSOURCE_BUFFER_ARRAY, AUSOURCE_DESCRIPTOR, AUSOURCE_FILE_POINTER, AUSOURCE_FEED } ausource_t; /* This used to define the types of searches that can be done. It is not used any more. */ typedef enum { AUSEARCH_UNSET, AUSEARCH_EXISTS, AUSEARCH_EQUAL, AUSEARCH_NOT_EQUAL, AUSEARCH_TIME_LT, AUSEARCH_TIME_LE, AUSEARCH_TIME_GE, AUSEARCH_TIME_GT, AUSEARCH_TIME_EQ, AUSEARCH_INTERPRETED = 0x40000000 } ausearch_op_t; /* This determines where to position the cursor when a search completes */ typedef enum { AUSEARCH_STOP_EVENT, AUSEARCH_STOP_RECORD, AUSEARCH_STOP_FIELD } austop_t; /* This defines how search rule pieces are treated to decide when * to stop a search */ typedef enum { AUSEARCH_RULE_CLEAR, AUSEARCH_RULE_OR, AUSEARCH_RULE_AND, AUSEARCH_RULE_REGEX } ausearch_rule_t; typedef struct { time_t sec; // Event seconds unsigned int milli; // millisecond of the timestamp unsigned long serial; // Serial number of the event const char *host; // Machine's name } au_event_t; /* This indicates why the user supplied callback was invoked */ typedef enum {AUPARSE_CB_EVENT_READY} auparse_cb_event_t; /* This determines the type of field at current cursor location * ONLY APPEND - DO NOT DELETE or it will break ABI */ typedef enum { AUPARSE_TYPE_UNCLASSIFIED, AUPARSE_TYPE_UID, AUPARSE_TYPE_GID, AUPARSE_TYPE_SYSCALL, AUPARSE_TYPE_ARCH, AUPARSE_TYPE_EXIT, AUPARSE_TYPE_ESCAPED, AUPARSE_TYPE_PERM, AUPARSE_TYPE_MODE, AUPARSE_TYPE_SOCKADDR, AUPARSE_TYPE_FLAGS, AUPARSE_TYPE_PROMISC, AUPARSE_TYPE_CAPABILITY, AUPARSE_TYPE_SUCCESS, AUPARSE_TYPE_A0, AUPARSE_TYPE_A1, AUPARSE_TYPE_A2, AUPARSE_TYPE_A3, AUPARSE_TYPE_SIGNAL, AUPARSE_TYPE_LIST, AUPARSE_TYPE_TTY_DATA, AUPARSE_TYPE_SESSION, AUPARSE_TYPE_CAP_BITMAP, AUPARSE_TYPE_NFPROTO, AUPARSE_TYPE_ICMPTYPE, AUPARSE_TYPE_PROTOCOL, AUPARSE_TYPE_ADDR, AUPARSE_TYPE_PERSONALITY, AUPARSE_TYPE_SECCOMP, AUPARSE_TYPE_OFLAG, AUPARSE_TYPE_MMAP, AUPARSE_TYPE_MODE_SHORT, AUPARSE_TYPE_MAC_LABEL, AUPARSE_TYPE_PROCTITLE, AUPARSE_TYPE_HOOK, AUPARSE_TYPE_NETACTION, AUPARSE_TYPE_MACPROTO, AUPARSE_TYPE_IOCTL_REQ, AUPARSE_TYPE_ESCAPED_KEY, AUPARSE_TYPE_ESCAPED_FILE, AUPARSE_TYPE_FANOTIFY, AUPARSE_TYPE_NLMCGRP, AUPARSE_TYPE_RESOLVE, AUPARSE_TYPE_TRUST, AUPARSE_TYPE_FAN_TYPE, AUPARSE_TYPE_FAN_INFO, AUPARSE_TYPE_ERRNO } auparse_type_t; /* This type determines what escaping if any gets applied to interpreted fields */ typedef enum { AUPARSE_ESC_RAW, AUPARSE_ESC_TTY, AUPARSE_ESC_SHELL, AUPARSE_ESC_SHELL_QUOTE } auparse_esc_t; /* This type determines what to destroy with the extended destroy function */ typedef enum { AUPARSE_DESTROY_ALL, AUPARSE_DESTROY_COMMON } auparse_destroy_what_t; /* auparse_normalize options */ typedef enum { NORM_OPT_ALL, NORM_OPT_NO_ATTRS} normalize_option_t; #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/auparse/auparse-idata.h000066400000000000000000000033411501761310600211500ustar00rootroot00000000000000/* * idata.h - Header file for ausearch-lookup.c * Copyright (c) 2013,2016-17,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef IDATA_HEADER #define IDATA_HEADER #include "config.h" #include "dso.h" #include "auparse-defs.h" typedef struct _idata { unsigned int machine; // The machine type for the event int syscall; // The syscall for the event unsigned long long a0; // arg 0 to the syscall unsigned long long a1; // arg 1 to the syscall const char *cwd; // The current working directory const char *name; // name of field being interpreted const char *val; // value of field being interpreted } idata; int auparse_interp_adjust_type(int rtype, const char *name, const char *val); char *auparse_do_interpretation(int type, const idata *id, auparse_esc_t escape_mode); void _auparse_load_interpretations(const char *buf); void _auparse_free_interpretations(void); const char *_auparse_lookup_interpretation(const char *name); void _auparse_flush_caches(void); #endif audit-userspace-4.0.5/auparse/auparse.c000066400000000000000000001452471501761310600200770ustar00rootroot00000000000000/* auparse.c -- * Copyright 2006-08,2012-23 Red Hat Inc. * All Rights Reserved. * * 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 General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include "expression.h" #include "internal.h" #include "auparse.h" #include "interpret.h" #include "auparse-idata.h" #include "libaudit.h" #include #include #include #include #include #include #include #include "common.h" //#define LOL_EVENTS_DEBUG01 1 // add debug for list of list event // processing #ifdef LOL_EVENTS_DEBUG01 static int debug = 0; #endif static time_t eoe_timeout = EOE_TIMEOUT; static void init_lib(void) __attribute__ ((constructor)); static void init_lib(void) { init_interpretation_list(); } /* like strchr except string is delimited by length, not null byte */ static char *strnchr(const char *s, int c, size_t n) { char *p_char; const char *p_end = s + n; for (p_char = (char *)s; p_char < p_end && *p_char != c; p_char++); if (p_char == p_end) return NULL; return p_char; } static int access_ok(const char *filename) { int rc = access(filename, R_OK); if (rc == 0) return rc; #ifdef HAVE_FACCESSAT // If we have faccessat, let's try effective ids. return faccessat(AT_FDCWD, filename, R_OK, AT_EACCESS); #else // If we don't, return what we have from access() return rc; #endif } static int setup_log_file_array(auparse_state_t *au) { struct daemon_conf config; char *filename, **tmp; int len, num = 0, i = 0; /* Load config so we know where logs are */ if (secure_getenv("AUPARSE_DEBUG")) set_aumessage_mode(au, MSG_STDERR, DBG_NO); aup_load_config(au, &config, TEST_SEARCH); /* for each file */ len = strlen(config.log_file) + 16; filename = malloc(len); if (!filename) { fprintf(stderr, "No memory\n"); aup_free_config(&config); return 1; } /* Find oldest log file */ snprintf(filename, len, "%s", config.log_file); do { if (access_ok(filename) != 0) break; num++; snprintf(filename, len, "%s.%d", config.log_file, num); } while (1); if (num == 0) { fprintf(stderr, "No log file\n"); aup_free_config(&config); free(filename); return 1; } num--; tmp = malloc((num+2)*sizeof(char *)); if (!tmp) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); aup_free_config(&config); free(filename); return 1; } /* Got it, now process logs from last to first */ if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else snprintf(filename, len, "%s", config.log_file); do { tmp[i++] = strdup(filename); /* Get next log file */ num--; if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else if (num == 0) snprintf(filename, len, "%s", config.log_file); else break; } while (1); aup_free_config(&config); free(filename); // Terminate the list tmp[i] = NULL; au->source_list = tmp; return 0; } /* * au_lol_create - Create and initialise the base List of List event structure * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * Rtns: * NULL - no memory * ptr - pointer to array of event nodes (au_lolnode) */ static au_lolnode *au_lol_create(au_lol *lol) { int sz = ARRAY_LIMIT * sizeof(au_lolnode); lol->maxi = -1; if ((lol->array = (au_lolnode *)malloc(sz)) == NULL) return NULL; lol->limit = ARRAY_LIMIT; memset(lol->array, 0x00, sz); return lol->array; } /* * au_lol_clear - Free or rest the base List of List event structure * * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * reset - flag to indicate a reset of the structure, or the complete * freeing of memory * Rtns: * void */ static void au_lol_clear(au_lol *lol, int reset) { int i; if (lol->array) { for (i = 0; i <= lol->maxi; i++) { if (lol->array[i].l) { aup_list_clear(lol->array[i].l); free(lol->array[i].l); } } } if (reset) { /* If resetting, we just zero fields */ if (lol->array) memset(lol->array, 0x00, lol->limit * sizeof(au_lolnode)); lol->maxi = -1; } else { /* If not resetting, we free everything */ if (lol->array) free(lol->array); lol->array = NULL; lol->maxi = -1; } } /* * au_lol_append - Add a new event to our base List of List structure * * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * l - event list structure (which contains an event's constituent records) * Rtns: * ptr - pointer to au_lolnode which holds the event list structure * NULL - failed to reallocate memory */ static au_lolnode *au_lol_append(au_lol *lol, event_list_t *l) { int i; size_t new_size; au_lolnode *ptr; for (i = 0; i < lol->limit; i++) { au_lolnode *cur = &lol->array[i]; if (cur->status == EBS_EMPTY) { cur->l = l; cur->status = EBS_BUILDING; if (i > lol->maxi) lol->maxi = i; return cur; } } /* Over ran the array, make it bigger */ new_size = sizeof(au_lolnode) * (lol->limit + ARRAY_LIMIT); ptr = realloc(lol->array, new_size); if (ptr) { lol->array = ptr; memset(&lol->array[lol->limit], 0x00, sizeof(au_lolnode) * ARRAY_LIMIT); lol->array[i].l = l; lol->array[i].status = EBS_BUILDING; lol->maxi = i; lol->limit += ARRAY_LIMIT; } return ptr; } /* * au_get_ready_event - Find the next COMPLETE event in our list and mark EMPTY * * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * is_test - do not mark the node EMPTY * Rtns: * ptr - pointer to complete node (possibly just marked empty) * NULL - no complete nodes exist */ static event_list_t *au_get_ready_event(auparse_state_t *au, int is_test) { int i; au_lol *lol = au->au_lo; au_lolnode *lowest = NULL; if (au->au_ready == 0) { //if (debug) printf("No events ready\n"); return NULL; } for (i=0; i<=lol->maxi; i++) { // Look for the event with the lowest timestamp au_lolnode *cur = &(lol->array[i]); if (cur->status == EBS_EMPTY) continue; // If we are just testing for a complete event, return if (is_test && cur->status == EBS_COMPLETE) return cur->l; if (lowest == NULL) lowest = cur; else if (auparse_timestamp_compare(&(lowest->l->e), &(cur->l->e)) == 1) lowest = cur; } if (lowest && lowest->status == EBS_COMPLETE) { lowest->status = EBS_EMPTY; au->au_ready--; return lowest->l; } return NULL; } /* * au_check_events - Run though all events marking those we can mark COMPLETE * * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * sec - time of current event from stream being processed. We use this to see * how old the events are we have in our list * Rtns: * void */ static void au_check_events(auparse_state_t *au, time_t sec) { rnode *r; int i; au_lol *lol = au->au_lo; for(i=0; i<=lol->maxi; i++) { au_lolnode *cur = &lol->array[i]; if (cur->status == EBS_BUILDING) { if ((r = aup_list_get_cur(cur->l)) == NULL) continue; // If eoe_timeout seconds have elapsed, we are done if (cur->l->e.sec + eoe_timeout <= sec) { cur->status = EBS_COMPLETE; au->au_ready++; } else if (audit_is_last_record(r->type)) { // If known to be 1 record event, we are done cur->status = EBS_COMPLETE; au->au_ready++; } } } } /* * au_terminate_all_events - Mark all events in 'BUILD' state to be COMPLETE * * Args: * lol - pointer to memory holding structure (eg the static au_lo variable) * Rtns: * void */ static void au_terminate_all_events(auparse_state_t *au) { int i; au_lol *lol = au->au_lo; for (i=0; i<=lol->maxi; i++) { au_lolnode *cur = &lol->array[i]; if (cur->status == EBS_BUILDING) { cur->status = EBS_COMPLETE; au->au_ready++; //if (debug) printf("%d events complete\n", au->au_ready); } } } #ifdef LOL_EVENTS_DEBUG01 /* * print_list_t - Print summary of event's records * Args: * l - event_list to print * Rtns: * void */ void print_list_t(event_list_t *l) { rnode *r; if (l == NULL) { printf("\n"); return; } printf("0x%p: %lld.%3.3u:%lu %s", l, (long long int)l->e.sec, l->e.milli, l->e.serial, l->e.host ? l->e.host : ""); printf(" cnt=%u", l->cnt); for (r = l->head; r != NULL; r = r->next) { printf(" {%d %d %u}", r->type, r->list_idx, r->line_number); } printf("\n"); } /* * lol_status - return type of event state as a character * Args: * s - event state * Rtns: * char - E, B or C for EMPTY, BUILDING or COMPLETE, or '*' for unknown */ static char lol_status(au_lol_t s) { switch(s) { case EBS_EMPTY: return 'E'; break; case EBS_BUILDING: return 'B'; break; case EBS_COMPLETE: return 'C'; break; } return '*'; } /* * print_lol - Print a list of list events and their records * Args: * label - String to act as label when printing * lol - pointer to memory holding structure (eg the static au_lo variable) * Rtns: * void */ void print_lol(char *label, au_lol *lol) { int i; printf("%s 0x%p: a: 0x%p, %d, %d\n", label, lol, lol->array, lol->maxi, lol->limit); if (debug > 1) for (i = 0; i <= lol->maxi; i++) { printf("{%2d 0x%p %c } ", i, (&lol->array[i]), lol_status(lol->array[i].status)); print_list_t(lol->array[i].l); } if (lol->maxi >= 0) printf("\n"); } #endif /* LOL_EVENTS_DEBUG01 */ /* General functions that affect operation of the library */ /* * au_setup_userspace_configitems - load userspace configuration items from auditd.conf * * Args: * au - pointer to auparseing state structure * * Rtns: * void */ static void au_setup_userspace_configitems(auparse_state_t *au) { struct daemon_conf config; /* Load config so we know where logs are */ if (secure_getenv("AUPARSE_DEBUG")) set_aumessage_mode(au, MSG_STDERR, DBG_NO); aup_load_config(au, &config, TEST_SEARCH); eoe_timeout = (time_t)config.end_of_event_timeout; aup_free_config(&config); } auparse_state_t *auparse_init(ausource_t source, const void *b) { char **tmp, **bb = (char **)b, *buf = (char *)b; int n, i; size_t size, len; auparse_state_t *au = malloc(sizeof(auparse_state_t)); if (au == NULL) { errno = ENOMEM; return NULL; } au->le = NULL; /* * Set up the List of List events base structure */ au->au_lo = calloc(sizeof(au_lol), 1); if (au->au_lo == NULL) { free(au); errno = ENOMEM; return NULL; } au_lol_clear(au->au_lo, 0); // python doesn't call auparse_destroy if (au_lol_create(au->au_lo) == NULL) { free(au->au_lo); free(au); errno = ENOMEM; return NULL; } au->au_ready = 0; au->escape_mode = AUPARSE_ESC_TTY; au->message_mode = MSG_QUIET; au->debug_message = DBG_NO; au->in = NULL; au->source_list = NULL; databuf_init(&au->databuf, 0, 0); au->callback = NULL; au->callback_user_data = NULL; au->callback_user_data_destroy = NULL; au_setup_userspace_configitems(au); switch (source) { case AUSOURCE_LOGS: if (setup_log_file_array(au)) goto bad_exit; break; case AUSOURCE_FILE: if (b == NULL) goto bad_exit; if (access_ok(b)) goto bad_exit; tmp = malloc(2*sizeof(char *)); if (tmp == NULL) goto bad_exit; tmp[0] = strdup(b); tmp[1] = NULL; au->source_list = tmp; break; case AUSOURCE_FILE_ARRAY: if (bb == NULL) goto bad_exit; n = 0; while (bb[n]) { if (access_ok(bb[n])) goto bad_exit; n++; } tmp = malloc((n+1)*sizeof(char *)); for (i=0; isource_list = tmp; break; case AUSOURCE_BUFFER: if (buf == NULL) goto bad_exit; len = strlen(buf); if (databuf_init(&au->databuf, len, DATABUF_FLAG_PRESERVE_HEAD) < 0) goto bad_exit; if (databuf_append(&au->databuf, buf, len) < 0) goto bad_exit; break; case AUSOURCE_BUFFER_ARRAY: if (bb == NULL) goto bad_exit; size = 0; for (n = 0; (buf = bb[n]); n++) { len = strlen(bb[n]); if (bb[n][len-1] != '\n') { size += len + 1; } else { size += len; } } if (databuf_init(&au->databuf, size, DATABUF_FLAG_PRESERVE_HEAD) < 0) goto bad_exit; for (n = 0; (buf = bb[n]); n++) { len = strlen(buf); if (databuf_append(&au->databuf, buf, len) < 0) goto bad_exit; } break; case AUSOURCE_DESCRIPTOR: n = (long)b; au->in = fdopen(n, "rm"); break; case AUSOURCE_FILE_POINTER: au->in = (FILE *)b; break; case AUSOURCE_FEED: if (databuf_init(&au->databuf, 0, 0) < 0) goto bad_exit; break; default: errno = EINVAL; goto bad_exit; break; } au->source = source; au->list_idx = 0; au->line_number = 0; au->next_buf = NULL; au->off = 0; au->cur_buf = NULL; au->line_pushed = 0; au->parse_state = EVENT_EMPTY; au->expr = NULL; au->find_field = NULL; au->search_where = AUSEARCH_STOP_EVENT; au->tmp_translation = NULL; init_normalizer(&au->norm_data); return au; bad_exit: databuf_free(&au->databuf); /* Free list of events list (au_lo) structure */ au_lol_clear(au->au_lo, 0); free(au->au_lo); free(au); return NULL; } void auparse_add_callback(auparse_state_t *au, auparse_callback_ptr callback, void *user_data, user_destroy user_destroy_func) { if (au == NULL) { errno = EINVAL; return; } if (au->callback_user_data_destroy) { (*au->callback_user_data_destroy)(au->callback_user_data); au->callback_user_data = NULL; } au->callback = callback; au->callback_user_data = user_data; au->callback_user_data_destroy = user_destroy_func; } static void consume_feed(auparse_state_t *au, int flush) { //if (debug) printf("consume feed, flush %d\n", flush); while (auparse_next_event(au) > 0) { if (au->callback) { (*au->callback)(au, AUPARSE_CB_EVENT_READY, au->callback_user_data); } } if (flush) { // FIXME: might need a call here to force auparse_next_event() // to consume any partial data not fully consumed. /* Terminate all outstanding events, as we are at end of input * (ie mark BUILDING events as COMPLETE events) then if we * have a callback execute the callback on each event * FIXME: Should we implement a 'checkpoint' concept as per * ausearch or accept these 'partial' events? */ event_list_t *l; //if (debug) printf("terminate all events in flush\n"); au_terminate_all_events(au); while ((l = au_get_ready_event(au, 0)) != NULL) { rnode *r; au->le = l; // make this current the event of interest aup_list_first(l); r = aup_list_get_cur(l); free_interpretation_list(); load_interpretation_list(r->interp); aup_list_first_field(l); if (au->callback) { (*au->callback)(au, AUPARSE_CB_EVENT_READY, au->callback_user_data); } } } } int auparse_new_buffer(auparse_state_t *au, const char *data, size_t data_len) { if (au->source != AUSOURCE_BUFFER) return 1; auparse_reset(au); if (databuf_replace(&au->databuf, data, data_len) < 0) return 1; return 0; } int auparse_feed(auparse_state_t *au, const char *data, size_t data_len) { if (databuf_append(&au->databuf, data, data_len) < 0) return -1; consume_feed(au, 0); return 0; } int auparse_flush_feed(auparse_state_t *au) { consume_feed(au, 1); return 0; } // If there is any data in the state machine, return 1. // Otherwise return 0 to indicate its empty int auparse_feed_has_data(const auparse_state_t *au) { if (!au) return 0; int i; au_lol *lol = au->au_lo; // An improvement would be to track how many events we have stored // to avoid a costly loop for (i=0; i <= lol->maxi; i++) { au_lolnode *cur = &(lol->array[i]); if (cur->status > EBS_EMPTY) return 1; } return 0; } // If there is a ready event in the state machine, return 1. // Otherwise return 0 to indicate its empty int auparse_feed_has_ready_event(auparse_state_t *au) { if (au_get_ready_event(au, 1) != NULL) return 1; return 0; } void auparse_feed_age_events(auparse_state_t *au) { time_t t = time(NULL); au_check_events(au, t); consume_feed(au, 0); } void auparse_set_escape_mode(auparse_state_t *au, auparse_esc_t mode) { if (au == NULL) return; au->escape_mode = mode; } /* * Non-public function. Subject to change. * buf is a string of name value pairs to be used for interpreting. * Calling this function automatically releases the previous list. */ void _auparse_load_interpretations(const char *buf) { free_interpretation_list(); if (buf == NULL) return; load_interpretation_list(buf); } /* * Non-public function. Subject to change. */ void _auparse_free_interpretations(void) { free_interpretation_list(); } int auparse_reset(auparse_state_t *au) { if (au == NULL) { errno = EINVAL; return -1; } /* Create or Free list of events list (au_lo) structure */ if (au->au_lo->array == NULL) au_lol_create(au->au_lo); else au_lol_clear(au->au_lo, 1); au->parse_state = EVENT_EMPTY; au->au_ready = 0; au->le = NULL; switch (au->source) { case AUSOURCE_LOGS: case AUSOURCE_FILE: case AUSOURCE_FILE_ARRAY: if (au->in) { fclose(au->in); au->in = NULL; } /* Fall through */ case AUSOURCE_DESCRIPTOR: case AUSOURCE_FILE_POINTER: if (au->in) rewind(au->in); /* Fall through */ case AUSOURCE_BUFFER: case AUSOURCE_BUFFER_ARRAY: au->list_idx = 0; au->line_number = 0; au->off = 0; databuf_reset(&au->databuf); break; default: return -1; } free_interpretation_list(); return 0; } char *auparse_metrics(const auparse_state_t *au) { char *metrics; unsigned int uid, gid; aulookup_metrics(&uid, &gid); if (asprintf(&metrics, "max lol available: %lu\n" "max lol used: %d\n" "pending lol: %d\n" "uid cache size: %u\n" "gid cache size: %u", au->au_lo->limit, au->au_lo->maxi, au->au_ready, uid, gid) < 0) metrics = NULL; return metrics; } /* Add EXPR to AU, using HOW to select the combining operator. On success, return 0. On error, free EXPR set errno and return -1. NOTE: EXPR is freed on error! */ static int add_expr(auparse_state_t *au, struct expr *expr, ausearch_rule_t how) { if (au->expr == NULL) au->expr = expr; else if (how == AUSEARCH_RULE_CLEAR) { expr_free(au->expr); au->expr = expr; } else { struct expr *e; e = expr_create_binary(how == AUSEARCH_RULE_OR ? EO_OR : EO_AND, au->expr, expr); if (e == NULL) { int err; err = errno; expr_free(expr); errno = err; return -1; } au->expr = e; } au->expr->started = 0; return 0; } static int ausearch_add_item_internal(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how, unsigned op_eq, unsigned op_ne) { struct expr *expr; // Make sure there's a field if (field == NULL) goto err_out; // Make sure how is within range if (how < AUSEARCH_RULE_CLEAR || how > AUSEARCH_RULE_AND) goto err_out; // All pre-checks are done, build a rule if (strcmp(op, "exists") == 0) expr = expr_create_field_exists(field); else { unsigned t_op; if (strcmp(op, "=") == 0) t_op = op_eq; else if (strcmp(op, "!=") == 0) t_op = op_ne; else goto err_out; if (value == NULL) goto err_out; expr = expr_create_comparison(field, t_op, value); } if (expr == NULL) return -1; if (add_expr(au, expr, how) != 0) return -1; /* expr is freed by add_expr() */ return 0; err_out: errno = EINVAL; return -1; } int ausearch_add_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how) { return ausearch_add_item_internal(au, field, op, value, how, EO_RAW_EQ, EO_RAW_NE); } int ausearch_add_interpreted_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how) { return ausearch_add_item_internal(au, field, op, value, how, EO_INTERPRETED_EQ, EO_INTERPRETED_NE); } int ausearch_add_timestamp_item_ex(auparse_state_t *au, const char *op, time_t sec, unsigned milli, unsigned serial, ausearch_rule_t how) { static const struct { unsigned value; const char name[3]; } ts_tab[] = { {EO_VALUE_LT, "<"}, {EO_VALUE_LE, "<="}, {EO_VALUE_GE, ">="}, {EO_VALUE_GT, ">"}, {EO_VALUE_EQ, "="}, }; struct expr *expr; size_t i; unsigned t_op; for (i = 0; i < sizeof(ts_tab) / sizeof(*ts_tab); i++) { if (strcmp(ts_tab[i].name, op) == 0) goto found_op; } goto err_out; found_op: t_op = ts_tab[i].value; if (milli >= 1000) goto err_out; // Make sure how is within range if (how < AUSEARCH_RULE_CLEAR || how > AUSEARCH_RULE_AND) goto err_out; // All pre-checks are done, build a rule expr = expr_create_timestamp_comparison_ex(t_op, sec, milli, serial); if (expr == NULL) return -1; if (add_expr(au, expr, how) != 0) return -1; /* expr is freed by add_expr() */ return 0; err_out: errno = EINVAL; return -1; } int ausearch_add_timestamp_item(auparse_state_t *au, const char *op, time_t sec, unsigned milli, ausearch_rule_t how) { return ausearch_add_timestamp_item_ex(au, op, sec, milli, 0, how); } int ausearch_add_expression(auparse_state_t *au, const char *expression, char **error, ausearch_rule_t how) { struct expr *expr; if (how < AUSEARCH_RULE_CLEAR || how > AUSEARCH_RULE_AND) goto err_einval; expr = expr_parse(expression, error); if (expr == NULL) { errno = EINVAL; return -1; } if (add_expr(au, expr, how) != 0) goto err; /* expr is freed by add_expr() */ return 0; err_einval: errno = EINVAL; err: *error = NULL; return -1; } int ausearch_add_regex(auparse_state_t *au, const char *regexp) { struct expr *expr; // Make sure there's an expression if (regexp == NULL) goto err_out; expr = expr_create_regexp_expression(regexp); if (expr == NULL) return -1; if (add_expr(au, expr, AUSEARCH_RULE_AND) != 0) return -1; /* expr is freed by add_expr() */ return 0; err_out: errno = EINVAL; return -1; } int ausearch_set_stop(auparse_state_t *au, austop_t where) { if (where < AUSEARCH_STOP_EVENT || where > AUSEARCH_STOP_FIELD) { errno = EINVAL; return -1; } au->search_where = where; return 0; } void ausearch_clear(auparse_state_t *au) { if (au->expr != NULL) { expr_free(au->expr); au->expr = NULL; } au->search_where = AUSEARCH_STOP_EVENT; } static void auparse_destroy_common(auparse_state_t *au) { if (au == NULL) return; if (au->source_list) { int n = 0; while (au->source_list[n]) free(au->source_list[n++]); free(au->source_list); au->source_list = NULL; } au->next_buf = NULL; free(au->cur_buf); au->cur_buf = NULL; au->le = NULL; au->parse_state = EVENT_EMPTY; free(au->find_field); au->find_field = NULL; ausearch_clear(au); databuf_free(&au->databuf); if (au->callback_user_data_destroy) { (*au->callback_user_data_destroy)(au->callback_user_data); au->callback_user_data = NULL; } if (au->in) { fclose(au->in); au->in = NULL; } free_interpretation_list(); clear_normalizer(&au->norm_data); au_lol_clear(au->au_lo, 0); free((void *)au->tmp_translation); free(au->au_lo); free(au); } void auparse_destroy(auparse_state_t *au) { _aulookup_destroy_uid_list(); aulookup_destroy_gid_list(); auparse_destroy_common(au); } void auparse_destroy_ext(auparse_state_t *au, auparse_destroy_what_t what) { if (what == AUPARSE_DESTROY_COMMON) auparse_destroy_common(au); else if (what == AUPARSE_DESTROY_ALL) auparse_destroy(au); return; } /* alloc a new buffer, cur_buf which contains a null terminated line * without a newline (note, this implies the line may be empty (strlen == 0)) if * successfully read a blank line (e.g. containing only a single newline). * cur_buf will have been newly allocated with malloc. * * Note: cur_buf will be freed the next time this routine is called if * cur_buf is not NULL, callers who retain a reference to the cur_buf * pointer will need to set cur_buf to NULL to cause the previous cur_buf * allocation to persist. * * Returns: * 1 if successful (errno == 0) * 0 if non-blocking input unavailable (errno == 0) * -1 if error (errno contains non-zero error code) * -2 if EOF (errno == 0) */ static int readline_file(auparse_state_t *au) { ssize_t rc; char *p_last_char; size_t n = 0; if (au->cur_buf != NULL) { free(au->cur_buf); au->cur_buf = NULL; } if (au->in == NULL) { errno = EBADF; return -1; } if ((rc = getline(&au->cur_buf, &n, au->in)) <= 0) { // Note: getline always malloc's if lineptr==NULL or n==0, // on failure malloc'ed memory is left uninitialized, // caller must free it. free(au->cur_buf); au->cur_buf = NULL; // Note: feof() does not set errno if (feof(au->in)) { // return EOF condition errno = 0; return -2; } // return error condition, error code in errno return -1; } p_last_char = au->cur_buf + (rc-1); if (*p_last_char == '\n') { /* nuke newline */ *p_last_char = 0; } // return success errno = 0; return 1; } /* malloc & copy a line into cur_buf from the internal buffer, * next_buf. cur_buf will contain a null terminated line without a * newline (note, this implies the line may be empty (strlen == 0)) if * successfully read a blank line (e.g. containing only a single * newline). * * Note: cur_buf will be freed the next time this routine is called if * cur_buf is not NULL, callers who retain a reference to the cur_buf * pointer will need to set cur_buf to NULL to cause the previous cur_buf * allocation to persist. * * Returns: * 1 if successful (errno == 0) * 0 if non-blocking input unavailable (errno == 0) * -1 if error (errno contains non-zero error code) * -2 if EOF (errno == 0) */ static int readline_buf(auparse_state_t *au) { char *p_newline=NULL; size_t line_len; if (au->cur_buf != NULL) { free(au->cur_buf); au->cur_buf = NULL; } //if (debug) databuf_print(&au->databuf, 1, "readline_buf"); if (au->databuf.len == 0) { // return EOF condition errno = 0; return -2; } if ((p_newline = strnchr(databuf_beg(&au->databuf), '\n', au->databuf.len)) != NULL) { line_len = p_newline - databuf_beg(&au->databuf); /* dup the line */ au->cur_buf = malloc(line_len+1); // +1 for null terminator if (au->cur_buf == NULL) return -1; // return error condition, errno set strncpy(au->cur_buf, databuf_beg(&au->databuf), line_len); au->cur_buf[line_len] = 0; if (databuf_advance(&au->databuf, line_len+1) < 0) return -1; // return success errno = 0; return 1; } else { // return no data available errno = 0; return 0; } } static int str2event(char *s, au_event_t *e) { char *ptr; errno = 0; e->sec = strtoul(s, NULL, 10); if (errno || e->sec > (LONG_MAX - eoe_timeout -1)) return -1; ptr = strchr(s, '.'); if (ptr) { ptr++; e->milli = strtoul(ptr, NULL, 10); if (errno || e->milli > 999) return -1; s = ptr; } else e->milli = 0; ptr = strchr(s, ':'); if (ptr) { ptr++; e->serial = strtoul(ptr, NULL, 10); if (errno) return -1; } else e->serial = 0; return 0; } #ifndef HAVE_STRNDUPA #define strndupa(s, n) \ ({ \ const char *__old = (s); \ size_t __len = strnlen (__old, (n)); \ char *__new = (char *) alloca(__len + 1); \ __new[__len] = '\0'; \ (char *) memcpy (__new, __old, __len); \ }) #endif /* Returns 0 on success and 1 on error */ static int extract_timestamp(const char *b, au_event_t *e) { char *ptr, *tmp; int rc = 1; e->host = NULL; if (*b == 'n') tmp = strndupa(b, 340); else tmp = strndupa(b, 80); ptr = audit_strsplit(tmp); if (ptr) { // Optionally grab the node - may or may not be included if (*ptr == 'n' && strnlen(ptr, 8) > 5) { e->host = strdup(ptr+5); (void)audit_strsplit(NULL);// Bump along to next one } // at this point we have type= ptr = audit_strsplit(NULL); // strlen is for fuzzers that make invalid lines if (ptr && strnlen(ptr, 20) > 18) { if (*(ptr+9) == '(') ptr+=9; else ptr = strchr(ptr, '('); if (ptr) { // now we should be pointed at the timestamp char *eptr; ptr++; eptr = strchr(ptr, ')'); if (eptr) *eptr = 0; if (str2event(ptr, e) == 0) rc = 0; } // else we have a bad line } // else we have a bad line } if (rc) free((void *)e->host); // else we have a bad line return rc; } static int events_are_equal(const au_event_t *e1, const au_event_t *e2) { // Check time & serial first since its most likely way // to spot 2 different events if (!(e1->serial == e2->serial && e1->milli == e2->milli && e1->sec == e2->sec)) return 0; // Hmm...same so far, check if both have a host, only a string // compare can tell if they are the same. Otherwise, if only one // of them have a host, they are definitely not the same. Its // a boundary on daemon config. if (e1->host && e2->host) { if (strcmp(e1->host, e2->host)) return 0; } else if (e1->host || e2->host) return 0; return 1; } /* This function will figure out how to get the next line of input. * storing it cur_buf. cur_buf will be NULL terminated but will not * contain a trailing newline. This implies a successful read * (result == 1) may result in a zero length cur_buf if a blank line * was read. * * cur_buf will have been allocated with malloc. The next time this * routine is called if cur_buf is non-NULL cur_buf will be freed, * thus if the caller wishes to retain a reference to malloc'ed * cur_buf data it should copy the cur_buf pointer and set cur_buf to * NULL. * * Returns: * 1 if successful (errno == 0) * 0 if non-blocking input unavailable (errno == 0) * -1 if error (errno contains non-zero error code) * -2 if EOF (errno == 0) */ static int retrieve_next_line(auparse_state_t *au) { int rc; // If line was pushed back for re-reading return that if (au->line_pushed) { // Starting new event, clear previous event data, // previous line is returned again for new parsing au->line_pushed = 0; au->line_number++; return 1; } switch (au->source) { case AUSOURCE_DESCRIPTOR: case AUSOURCE_FILE_POINTER: rc = readline_file(au); if (rc > 0) au->line_number++; return rc; case AUSOURCE_LOGS: case AUSOURCE_FILE: case AUSOURCE_FILE_ARRAY: // if the first time through, open file if (au->list_idx == 0 && au->in == NULL && au->source_list != NULL) { if (au->source_list[au->list_idx] == NULL) { errno = 0; return -2; } au->line_number = 0; au->in = fopen(au->source_list[au->list_idx], "rm"); if (au->in == NULL) return -1; __fsetlocking(au->in, FSETLOCKING_BYCALLER); } // loop reading lines from a file while (au->in) { if ((rc = readline_file(au)) == -2) { // end of file, open next file, // try readline again fclose(au->in); au->in = NULL; au->list_idx++; au->line_number = 0; if (au->source_list[au->list_idx]) { au->in = fopen( au->source_list[au->list_idx], "rm"); if (au->in == NULL) return -1; __fsetlocking(au->in, FSETLOCKING_BYCALLER); } } else { if (rc > 0) au->line_number++; return rc; } } return -2; // return EOF case AUSOURCE_BUFFER: case AUSOURCE_BUFFER_ARRAY: rc = readline_buf(au); if (rc > 0) au->line_number++; return rc; case AUSOURCE_FEED: rc = readline_buf(au); // No such thing as EOF for feed, translate EOF // to data not available if (rc == -2) return 0; else if (rc > 0) au->line_number++; return rc; default: return -1; } return -1; /* should never reach here */ } /******* * Functions that traverse events. ********/ static int ausearch_reposition_cursors(const auparse_state_t *au) { int rc = 0; switch (au->search_where) { case AUSEARCH_STOP_EVENT: aup_list_first(au->le); aup_list_first_field(au->le); break; case AUSEARCH_STOP_RECORD: aup_list_first_field(au->le); break; case AUSEARCH_STOP_FIELD: // do nothing - this is the normal stopping point break; default: rc = -1; break; } return rc; } /* This is called during search once per each record. It walks the list * of nvpairs and decides if a field matches. */ static int ausearch_compare(auparse_state_t *au) { rnode *r; if (au->le == NULL) return 0; r = aup_list_get_cur(au->le); if (r) { int res = expr_eval(au, r, au->expr); return res; } return 0; } // Returns < 0 on error, 0 no data, > 0 success int ausearch_cur_event(auparse_state_t* au) { int rc, records; if (au->expr == NULL) { errno = EINVAL; return -1; } records = auparse_get_num_records(au); for (int i = 0; i < records; i++) { if (auparse_goto_record_num(au, i) != 1) return -1; if ((rc = ausearch_compare(au)) > 0) { ausearch_reposition_cursors(au); return 1; } else if (rc < 0) return rc; } return 0; } // Returns < 0 on error, 0 no data, > 0 success int ausearch_next_event(auparse_state_t *au) { int rc; if (au->expr == NULL) { errno = EINVAL; return -1; } if (au->expr->started == 0) { if ((rc = auparse_first_record(au)) <= 0) return rc; au->expr->started = 1; } else { if ((rc = auparse_next_event(au)) <= 0) return rc; } do { do { if ((rc = ausearch_compare(au)) > 0) { ausearch_reposition_cursors(au); return 1; } else if (rc < 0) return rc; } while ((rc = auparse_next_record(au)) > 0); if (rc < 0) return rc; } while ((rc = auparse_next_event(au)) > 0); if (rc < 0) return rc; return 0; } /* * au_auparse_next_event - Get the next complete event * Args: * au - the parser state machine * Rtns: * < 0 - error * == 0 - no data * > 0 - we have an event and it's set to the 'current event' au->le */ static int au_auparse_next_event(auparse_state_t *au) { int rc, i, built; event_list_t *l; au_event_t e; /* * Deal with Python memory management issues where it issues a * auparse_destroy() call after an auparse_init() call but then wants * to still work with auparse data. Basically, we assume if the user * wants to parse for events (calling auparse_next_event()) we accept * that they expect the memory structures to exist. This is a bit * 'disconcerting' but the au_lol capability is a patch trying to * redress a singleton approach to event processing. */ if (au->au_lo->array == NULL && au->au_lo->maxi == -1) { #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("Creating lol array\n"); #endif /* LOL_EVENTS_DEBUG01 */ au_lol_create(au->au_lo); } /* * First see if we have any empty events but with an allocated event * list. These would have just been processed, so we can free them */ for (i = 0; i <= au->au_lo->maxi; i++) { au_lolnode *cur = &au->au_lo->array[i]; if (cur->status == EBS_EMPTY && cur->l) { #ifdef LOL_EVENTS_DEBUG01 if (debug) { printf("Freeing at start "); print_list_t(cur->l); } #endif /* LOL_EVENTS_DEBUG01 */ aup_list_clear(cur->l); free(cur->l); au->le = NULL; // this should crash any usage // of au->le until reset cur->l = NULL; } } /* * Now see if we have completed events queued, and if so grab the * first one and set it to be the 'current' event of interest */ if ((l = au_get_ready_event(au, 0)) != NULL) { rnode *r; aup_list_first(l); r = aup_list_get_cur(l); free_interpretation_list(); load_interpretation_list(r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 if (debug) print_lol("upfront", au->au_lo); #endif /* LOL_EVENTS_DEBUG01 */ return 1; } /* * If no complete events are available, lets ingest */ while (1) { for (i = 0; i <= au->au_lo->maxi; i++) { au_lolnode *cur = &au->au_lo->array[i]; if (cur->status == EBS_EMPTY && cur->l) { #ifdef LOL_EVENTS_DEBUG01 if (debug) { printf("Freeing at loop"); print_list_t(cur->l); } #endif /* LOL_EVENTS_DEBUG01 */ aup_list_clear(cur->l); free(cur->l); au->le = NULL; /* this should crash any usage of au->le until reset */ cur->l = NULL; } } rc = retrieve_next_line(au); #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("next_line(%d) '%s'\n", rc, au->cur_buf); #endif /* LOL_EVENTS_DEBUG01 */ if (rc == 0) { #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("Empty line\n"); #endif /* LOL_EVENTS_DEBUG01 */ return 0; /* NO data now */ } if (rc == -2) { /* * We are at EOF, so see if we have any accumulated * events. */ #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("EOF\n"); #endif /* LOL_EVENTS_DEBUG01 */ au_terminate_all_events(au); if ((l = au_get_ready_event(au, 0)) != NULL) { rnode *r; aup_list_first(l); r = aup_list_get_cur(l); free_interpretation_list(); load_interpretation_list(r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 if (debug) print_lol("eof termination", au->au_lo); #endif /* LOL_EVENTS_DEBUG01 */ return 1; } return 0; } else if (rc < 0) { #ifdef LOL_EVENTS_DEBUG01 /* Straight error */ if (debug) printf("Error %d\n", rc); #endif /* LOL_EVENTS_DEBUG01 */ return -1; } /* So we got a successful read ie rc > 0 */ if (extract_timestamp(au->cur_buf, &e)) { #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("Malformed line:%s\n", au->cur_buf); #endif /* LOL_EVENTS_DEBUG01 */ continue; } /* * Is this an event we have already been building? */ built = 0; for (i = 0; i <= au->au_lo->maxi; i++) { au_lolnode *cur = &au->au_lo->array[i]; if (cur->status == EBS_BUILDING) { if (events_are_equal(&cur->l->e, &e)) { #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("Adding event to building event\n"); #endif /* LOL_EVENTS_DEBUG01 */ if (aup_list_append(cur->l, au->cur_buf, au->list_idx, au->line_number) < 0) { au->cur_buf = NULL; continue; } au->cur_buf = NULL; free((char *)e.host); au_check_events(au, e.sec); #ifdef LOL_EVENTS_DEBUG01 if (debug) print_lol("building",au->au_lo); #endif /* LOL_EVENTS_DEBUG01 */ /* we built something, so break out */ built++; break; } } } if (built) continue; /* So create one */ #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("First record in new event, initialize event\n"); #endif /* LOL_EVENTS_DEBUG01 */ if ((l=(event_list_t *)malloc(sizeof(event_list_t))) == NULL) { free((char *)e.host); return -1; } aup_list_create(l); aup_list_set_event(l, &e); if (aup_list_append(l, au->cur_buf, au->list_idx, au->line_number) < 0) { au->cur_buf = NULL; aup_list_clear(l); free(l); continue; } // Eat standalone EOE - main event was already marked complete if (l->head->type == AUDIT_EOE) { au->cur_buf = NULL; aup_list_clear(l); free(l); continue; } if (au_lol_append(au->au_lo, l) == NULL) { free((char *)e.host); au->cur_buf = NULL; aup_list_clear(l); free(l); #ifdef LOL_EVENTS_DEBUG01 if (debug) printf("error appending to lol\n"); #endif /* LOL_EVENTS_DEBUG01 */ return -1; } au->cur_buf = NULL; free((char *)e.host); au_check_events(au, e.sec); if ((l = au_get_ready_event(au, 0)) != NULL) { rnode *r; aup_list_first(l); r = aup_list_get_cur(l); free_interpretation_list(); load_interpretation_list(r->interp); aup_list_first_field(l); au->le = l; #ifdef LOL_EVENTS_DEBUG01 if (debug) print_lol("basic", au->au_lo); #endif /* LOL_EVENTS_DEBUG01 */ return 1; } } } // Brute force go to next event. Returns < 0 on error, 0 no data, > 0 success int auparse_next_event(auparse_state_t *au) { clear_normalizer(&au->norm_data); return au_auparse_next_event(au); } /* Accessors to event data */ const au_event_t *auparse_get_timestamp(const auparse_state_t *au) { if (au && au->le && au->le->e.sec != 0) return &au->le->e; else return NULL; } time_t auparse_get_time(const auparse_state_t *au) { if (au && au->le) return au->le->e.sec; else return 0; } unsigned int auparse_get_milli(const auparse_state_t *au) { if (au && au->le) return au->le->e.milli; else return 0; } unsigned long auparse_get_serial(const auparse_state_t *au) { if (au && au->le) return au->le->e.serial; else return 0; } // Gets the machine node name const char *auparse_get_node(const auparse_state_t *au) { if (au && au->le && au->le->e.host != NULL) return strdup(au->le->e.host); else return NULL; } int auparse_node_compare(const au_event_t *e1, const au_event_t *e2) { // If both have a host, only a string compare can tell if they // are the same. Otherwise, if only one of them have a host, they // are definitely not the same. Its a boundary on daemon config. if (e1->host && e2->host) return strcmp(e1->host, e2->host); else if (e1->host) return 1; else if (e2->host) return -1; return 0; } int auparse_timestamp_compare(const au_event_t *e1, const au_event_t *e2) { if (e1->sec > e2->sec) return 1; if (e1->sec < e2->sec) return -1; if (e1->milli > e2->milli) return 1; if (e1->milli < e2->milli) return -1; if (e1->serial > e2->serial) return 1; if (e1->serial < e2->serial) return -1; return 0; } unsigned int auparse_get_num_records(const auparse_state_t *au) { // Its OK if au->le == NULL because get_cnt handles it return aup_list_get_cnt(au->le); } unsigned int auparse_get_record_num(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) return r->item; return 0; } /* Functions that traverse records in the same event */ int auparse_first_record(auparse_state_t *au) { int rc; rnode *r; // Its OK if au->le == NULL because get_cnt handles it if (aup_list_get_cnt(au->le) == 0) { // This function loads interpretations rc = auparse_next_event(au); if (rc <= 0) return rc; } r = aup_list_get_cur(au->le); if (r && r->item == 0 && interpretation_list_cnt()) { // If we are on the first record and the list has previously // been loaded, just pull cursor back and avoid loading the // interpretation list. aup_list_first_field(au->le); return 1; } aup_list_first(au->le); r = aup_list_get_cur(au->le); free_interpretation_list(); load_interpretation_list(r->interp); aup_list_first_field(au->le); return 1; } /* * Returns: -1 if an error occurs, * 0 if no more records in current event, * 1 for success. */ int auparse_next_record(auparse_state_t *au) { rnode *r; free_interpretation_list(); // Its OK if au->le == NULL because get_cnt handles it if (aup_list_get_cnt(au->le) == 0) { int rc = auparse_first_record(au); if (rc <= 0) return rc; } r = aup_list_next(au->le); if (r) { load_interpretation_list(r->interp); return 1; } else return 0; } int auparse_goto_record_num(const auparse_state_t *au, unsigned int num) { rnode *r; r = aup_list_get_cur(au->le); if (r && r->item == num && interpretation_list_cnt()) { // If we are on the first record and the list has previously // been loaded, just pull cursor back and avoid loading the // interpretation list. aup_list_first_field(au->le); return 1; } /* Check if a request is out of range */ free_interpretation_list(); // Its OK if au->le == NULL because get_cnt handles it if (num >= aup_list_get_cnt(au->le)) return 0; r = aup_list_goto_rec(au->le, num); if (r != NULL) { load_interpretation_list(r->interp); aup_list_first_field(au->le); return 1; } else return 0; } /* Accessors to record data */ int auparse_get_type(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) return r->type; else return 0; } const char *auparse_get_type_name(const auparse_state_t *au) { if (au->le == NULL) return NULL; rnode *r = aup_list_get_cur(au->le); if (r) return audit_msg_type_to_name(r->type); else return NULL; } unsigned int auparse_get_line_number(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) return r->line_number; else return 0; } const char *auparse_get_filename(const auparse_state_t *au) { switch (au->source) { case AUSOURCE_FILE: case AUSOURCE_FILE_ARRAY: break; default: return NULL; } if (au->le == NULL) return NULL; rnode *r = aup_list_get_cur(au->le); if (r) { if (r->list_idx < 0) return NULL; return au->source_list[r->list_idx]; } else { return NULL; } } int auparse_first_field(const auparse_state_t *au) { if (au->le == NULL) return 0; return aup_list_first_field(au->le); } int auparse_next_field(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) { if (nvlist_next(&r->nv)) return 1; else return 0; } return 0; } unsigned int auparse_get_num_fields(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) return nvlist_get_cnt(&r->nv); else return 0; } const char *auparse_get_record_text(const auparse_state_t *au) { if (au->le == NULL) return NULL; rnode *r = aup_list_get_cur(au->le); if (r) return r->record; else return NULL; } const char *auparse_get_record_interpretations(const auparse_state_t *au) { if (au->le == NULL) return NULL; rnode *r = aup_list_get_cur(au->le); if (r) return r->interp; else return NULL; } /* scan from current location to end of event */ const char *auparse_find_field(auparse_state_t *au, const char *name) { if (au->le == NULL) return NULL; free(au->find_field); au->find_field = strdup(name); if (au->le->e.sec) { const char *cur_name; rnode *r; // look at current record before moving r = aup_list_get_cur(au->le); if (r == NULL) return NULL; cur_name = nvlist_get_cur_name(&r->nv); if (cur_name && strcmp(cur_name, name) == 0) return nvlist_get_cur_val(&r->nv); return auparse_find_field_next(au); } return NULL; } /* Increment 1 location and then scan for next field */ const char *auparse_find_field_next(const auparse_state_t *au) { if (au->le == NULL) return NULL; if (au->find_field == NULL) { errno = EINVAL; return NULL; } if (au->le->e.sec) { int moved = 0; rnode *r = aup_list_get_cur(au->le); while (r) { // For each record in the event... if (!moved) { if (nvlist_next(&r->nv) == NULL) return NULL; moved=1; } if (nvlist_find_name(&r->nv, au->find_field)) return nvlist_get_cur_val(&r->nv); r = aup_list_next(au->le); if (r) { aup_list_first_field(au->le); free_interpretation_list(); load_interpretation_list(r->interp); } } } return NULL; } /* Accessors to field data */ unsigned int auparse_get_field_num(const auparse_state_t *au) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) { nvnode *n = nvlist_get_cur(&r->nv); if (n) return n->item; } return 0; } int auparse_goto_field_num(const auparse_state_t *au, unsigned int num) { if (au->le == NULL) return 0; rnode *r = aup_list_get_cur(au->le); if (r) { if (num >= r->nv.cnt) return 0; if ((nvlist_goto_rec(&r->nv, num))) return 1; } return 0; } const char *auparse_get_field_name(const auparse_state_t *au) { if (au->le == NULL) return NULL; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r) return nvlist_get_cur_name(&r->nv); } return NULL; } const char *auparse_get_field_str(const auparse_state_t *au) { if (au->le == NULL) return NULL; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r) return nvlist_get_cur_val(&r->nv); } return NULL; } int auparse_get_field_type(const auparse_state_t *au) { if (au->le == NULL) return AUPARSE_TYPE_UNCLASSIFIED; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r) return nvlist_get_cur_type(r); } return AUPARSE_TYPE_UNCLASSIFIED; } int auparse_get_field_int(const auparse_state_t *au) { const char *v = auparse_get_field_str(au); if (v) { int val; errno = 0; val = strtol(v, NULL, 10); if (errno == 0) return val; } else errno = ENODATA; return -1; } const char *auparse_interpret_field(auparse_state_t *au) { if (au->le == NULL) return NULL; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r) { r->cwd = NULL; return nvlist_interp_cur_val(r, au->escape_mode); } } return NULL; } const char *auparse_interpret_realpath(const auparse_state_t *au) { if (au->le == NULL) return NULL; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r) { if (nvlist_get_cur_type(r) != AUPARSE_TYPE_ESCAPED_FILE) return NULL; // Tell it to make a realpath r->cwd = au->le->cwd; return nvlist_interp_cur_val(r, au->escape_mode); } } return NULL; } static const char *auparse_interpret_sock_parts(auparse_state_t *au, const char *field) { if (au->le == NULL) return NULL; if (au->le->e.sec) { rnode *r = aup_list_get_cur(au->le); if (r == NULL) return NULL; // This is limited to socket address fields if (nvlist_get_cur_type(r) != AUPARSE_TYPE_SOCKADDR) return NULL; // Get interpretation const char *val = nvlist_interp_cur_val(r, au->escape_mode); if (val == NULL) return NULL; // make a copy since we modify it char *tmp = strdup(val); if (tmp == NULL) return NULL; // Locate the address part val = strstr(tmp, field); if (val) { // Get past the = val += strlen(field); // find other side char *ptr = strchr(val, ' '); if (ptr) { // terminate, copy, and return it *ptr = 0; const char *final = strdup(val); free(tmp); free((void *)au->tmp_translation); au->tmp_translation = final; return final; } } free(tmp); } return NULL; } const char *auparse_interpret_sock_family(auparse_state_t *au) { return auparse_interpret_sock_parts(au, "fam="); } const char *auparse_interpret_sock_port(auparse_state_t *au) { return auparse_interpret_sock_parts(au, "lport="); } const char *auparse_interpret_sock_address(auparse_state_t *au) { return auparse_interpret_sock_parts(au, "laddr="); } /* * auparse_set_eoe_timeout - set the end of event timeout value * * Args * new_tmo - new timeout value * Rtns * 0 - correctly set * 1 - failed to set */ int auparse_set_eoe_timeout (time_t new_tmo) { if (new_tmo == 0) return 1; eoe_timeout = new_tmo; return 0; } audit-userspace-4.0.5/auparse/auparse.h000066400000000000000000000165211501761310600200740ustar00rootroot00000000000000/* auparse.h -- * Copyright 2006-08,2012-23 Red Hat Inc. * All Rights Reserved. * * 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUPARSE_HEADER #define AUPARSE_HEADER #include "auparse-defs.h" #ifndef __attr_access # define __attr_access(x) #endif #ifndef __attr_dealloc # define __attr_dealloc(dealloc, argno) # define __attr_dealloc_free #endif #ifndef __attribute_malloc__ # define __attribute_malloc__ #endif #ifdef __cplusplus extern "C" { #endif /* Library type definitions */ /* opaque data type used for maintaining library state */ typedef struct opaque auparse_state_t; typedef void (*user_destroy)(void *user_data); typedef void (*auparse_callback_ptr)(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); /* General functions that affect operation of the library */ void auparse_destroy(auparse_state_t *au); void auparse_destroy_ext(auparse_state_t *au, auparse_destroy_what_t what); auparse_state_t *auparse_init(ausource_t source, const void *b) __attribute_malloc__ __attr_dealloc (auparse_destroy, 1); int auparse_new_buffer(auparse_state_t *au, const char *data, size_t data_len) __attr_access ((__read_only__, 2, 3)); int auparse_feed(auparse_state_t *au, const char *data, size_t data_len) __attr_access ((__read_only__, 2, 3)); void auparse_feed_age_events(auparse_state_t *au); int auparse_flush_feed(auparse_state_t *au); int auparse_feed_has_data(const auparse_state_t *au); int auparse_feed_has_ready_event(auparse_state_t *au); void auparse_add_callback(auparse_state_t *au, auparse_callback_ptr callback, void *user_data, user_destroy user_destroy_func); void auparse_set_escape_mode(auparse_state_t *au, auparse_esc_t mode); int auparse_reset(auparse_state_t *au); char *auparse_metrics(const auparse_state_t *au) __attr_dealloc_free; /* Functions that are part of the search interface */ int ausearch_add_expression(auparse_state_t *au, const char *expression, char **error, ausearch_rule_t how); int ausearch_add_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how); int ausearch_add_interpreted_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how); int ausearch_add_timestamp_item(auparse_state_t *au, const char *op, time_t sec, unsigned milli, ausearch_rule_t how); int ausearch_add_timestamp_item_ex(auparse_state_t *au, const char *op, time_t sec, unsigned milli, unsigned serial, ausearch_rule_t how); int ausearch_add_regex(auparse_state_t *au, const char *regexp); int ausearch_set_stop(auparse_state_t *au, austop_t where); void ausearch_clear(auparse_state_t *au); /* Function dealing with setting user space configuration items */ int auparse_set_eoe_timeout (time_t new_tmo); /* Functions that are part of the auparse_normalize interface */ // This causes the current event to become normalized. int auparse_normalize(auparse_state_t *au, normalize_option_t opt); // Event kind accessor const char *auparse_normalize_get_event_kind(const auparse_state_t *au); // session accessor int auparse_normalize_session(auparse_state_t *au); // Subject accessing functions int auparse_normalize_subject_primary(auparse_state_t *au); int auparse_normalize_subject_secondary(auparse_state_t *au); const char *auparse_normalize_subject_kind(const auparse_state_t *au); int auparse_normalize_subject_first_attribute(auparse_state_t *au); int auparse_normalize_subject_next_attribute(auparse_state_t *au); // Action string accessor const char *auparse_normalize_get_action(const auparse_state_t *au); // Object accessing functions int auparse_normalize_object_primary(auparse_state_t *au); int auparse_normalize_object_secondary(auparse_state_t *au); int auparse_normalize_object_primary2(auparse_state_t *au); int auparse_normalize_object_first_attribute(auparse_state_t *au); int auparse_normalize_object_next_attribute(auparse_state_t *au); const char *auparse_normalize_object_kind(const auparse_state_t *au); // Results accessor int auparse_normalize_get_results(auparse_state_t *au); // How accessor const char *auparse_normalize_how(const auparse_state_t *au); // Syscall key accessor int auparse_normalize_key(auparse_state_t *au); /* Functions that traverse events */ int ausearch_next_event(auparse_state_t *au); int ausearch_cur_event(auparse_state_t* au); int auparse_next_event(auparse_state_t *au); /* Accessors to event data */ const au_event_t *auparse_get_timestamp(const auparse_state_t *au); time_t auparse_get_time(const auparse_state_t *au); unsigned int auparse_get_milli(const auparse_state_t *au); unsigned long auparse_get_serial(const auparse_state_t *au); const char *auparse_get_node(const auparse_state_t *au) __attr_dealloc_free; int auparse_node_compare(const au_event_t *e1, const au_event_t *e2); int auparse_timestamp_compare(const au_event_t *e1, const au_event_t *e2); unsigned int auparse_get_num_records(const auparse_state_t *au); /* Functions that traverse records in the same event */ int auparse_first_record(auparse_state_t *au); int auparse_next_record(auparse_state_t *au); unsigned int auparse_get_record_num(const auparse_state_t *au); int auparse_goto_record_num(const auparse_state_t *au, unsigned int num); /* Accessors to record data */ int auparse_get_type(const auparse_state_t *au); const char *auparse_get_type_name(const auparse_state_t *au); unsigned int auparse_get_line_number(const auparse_state_t *au); const char *auparse_get_filename(const auparse_state_t *au); int auparse_first_field(const auparse_state_t *au); int auparse_next_field(const auparse_state_t *au); unsigned int auparse_get_num_fields(const auparse_state_t *au); const char *auparse_get_record_text(const auparse_state_t *au); const char *auparse_get_record_interpretations(const auparse_state_t *au); const char *auparse_find_field(auparse_state_t *au, const char *name); const char *auparse_find_field_next(const auparse_state_t *au); unsigned int auparse_get_field_num(const auparse_state_t *au); int auparse_goto_field_num(const auparse_state_t *au, unsigned int num); /* Accessors to field data */ const char *auparse_get_field_name(const auparse_state_t *au); const char *auparse_get_field_str(const auparse_state_t *au); int auparse_get_field_type(const auparse_state_t *au); int auparse_get_field_int(const auparse_state_t *au); const char *auparse_interpret_field(auparse_state_t *au); const char *auparse_interpret_realpath(const auparse_state_t *au); const char *auparse_interpret_sock_family(auparse_state_t *au); const char *auparse_interpret_sock_port(auparse_state_t *au); const char *auparse_interpret_sock_address(auparse_state_t *au); #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/auparse/auparse.pc.in000066400000000000000000000004151501761310600206470ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libauparse Description: Library for apps that want to parse and interpret audit events Version: @VERSION@ Libs: -L${libdir} -lauparse Libs.private: -laudit Cflags: -I${includedir} audit-userspace-4.0.5/auparse/bpftab.h000066400000000000000000000036311501761310600176700ustar00rootroot00000000000000/* bpftab.h -- * Copyright 2018-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/bpf.h */ _S(0, "BPF_MAP_CREATE") _S(1, "BPF_MAP_LOOKUP_ELEM") _S(2, "BPF_MAP_UPDATE_ELEM") _S(3, "BPF_MAP_DELETE_ELEM") _S(4, "BPF_MAP_GET_NEXT_KEY") _S(5, "BPF_PROG_LOAD") _S(6, "BPF_OBJ_PIN") _S(7, "BPF_OBJ_GET") _S(8, "BPF_PROG_ATTACH") _S(9, "BPF_PROG_DETACH") _S(10, "BPF_PROG_TEST_RUN") _S(11, "BPF_PROG_GET_NEXT_ID") _S(12, "BPF_MAP_GET_NEXT_ID") _S(13, "BPF_PROG_GET_FD_BY_ID") _S(14, "BPF_MAP_GET_FD_BY_ID") _S(15, "BPF_OBJ_GET_INFO_BY_FD") _S(16, "BPF_PROG_QUERY") _S(17, "BPF_RAW_TRACEPOINT_OPEN") _S(18, "BPF_BTF_LOAD") _S(19, "BPF_BTF_GET_FD_BY_ID") _S(20, "BPF_TASK_FD_QUERY") _S(21, "BPF_MAP_LOOKUP_AND_DELETE_ELEM") _S(22, "BPF_MAP_FREEZE") _S(23, "BPF_BTF_GET_NEXT_ID") _S(24, "BPF_MAP_LOOKUP_BATCH") _S(25, "BPF_MAP_LOOKUP_AND_DELETE_BATCH") _S(26, "BPF_MAP_UPDATE_BATCH") _S(27, "BPF_MAP_DELETE_BATCH") _S(28, "BPF_LINK_CREATE") _S(29, "BPF_LINK_UPDATE") _S(30, "BPF_LINK_GET_FD_BY_ID") _S(31, "BPF_LINK_GET_NEXT_ID") _S(32, "BPF_ENABLE_STATS") _S(33, "BPF_ITER_CREATE") _S(34, "BPF_LINK_DETACH") _S(35, "BPF_PROG_BIND_MAP") audit-userspace-4.0.5/auparse/captab.h000066400000000000000000000035201501761310600176610ustar00rootroot00000000000000/* captab.h -- * Copyright 2007,2008,2012-14,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/capability.h */ _S(0, "chown" ) _S(1, "dac_override" ) _S(2, "dac_read_search" ) _S(3, "fowner" ) _S(4, "fsetid" ) _S(5, "kill" ) _S(6, "setgid" ) _S(7, "setuid" ) _S(8, "setpcap" ) _S(9, "linux_immutable" ) _S(10, "net_bind_service" ) _S(11, "net_broadcast" ) _S(12, "net_admin" ) _S(13, "net_raw" ) _S(14, "ipc_lock" ) _S(15, "ipc_owner" ) _S(16, "sys_module" ) _S(17, "sys_rawio" ) _S(18, "sys_chroot" ) _S(19, "sys_ptrace" ) _S(20, "sys_pacct" ) _S(21, "sys_admin" ) _S(22, "sys_boot" ) _S(23, "sys_nice" ) _S(24, "sys_resource" ) _S(25, "sys_time" ) _S(26, "sys_tty_config" ) _S(27, "mknod" ) _S(28, "lease" ) _S(29, "audit_write" ) _S(30, "audit_control" ) _S(31, "setfcap" ) _S(32, "mac_override" ) _S(33, "mac_admin" ) _S(34, "syslog" ) _S(35, "wake_alarm" ) _S(36, "block_suspend" ) _S(37, "audit_read" ) _S(38, "perfmon" ) _S(39, "bpf" ) _S(40, "checkpoint_restore" ) audit-userspace-4.0.5/auparse/clocktab.h000066400000000000000000000023741501761310600202170ustar00rootroot00000000000000/* clocktab.h -- * Copyright 2012,2014 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/time.h */ _S(0, "CLOCK_REALTIME" ) _S(1, "CLOCK_MONOTONIC" ) _S(2, "CLOCK_PROCESS_CPUTIME_ID" ) _S(3, "CLOCK_THREAD_CPUTIME_ID" ) _S(4, "CLOCK_MONOTONIC_RAW" ) _S(5, "CLOCK_REALTIME_COARSE" ) _S(6, "CLOCK_MONOTONIC_COARSE" ) _S(7, "CLOCK_BOOTTIME" ) _S(8, "CLOCK_REALTIME_ALARM" ) _S(9, "CLOCK_BOOTTIME_ALARM" ) _S(10, "CLOCK_SGI_CYCLE" ) _S(11, "CLOCK_TAI" ) audit-userspace-4.0.5/auparse/clone-flagtab.h000066400000000000000000000034741501761310600211350ustar00rootroot00000000000000/* clone-flagtab.h -- * Copyright 2007,2012-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330ULL, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/sched.h */ _S(0x000000100ULL, "CLONE_VM" ) _S(0x000000200ULL, "CLONE_FS" ) _S(0x000000400ULL, "CLONE_FILES" ) _S(0x000000800ULL, "CLONE_SIGHAND" ) _S(0x000002000ULL, "CLONE_PTRACE" ) _S(0x000004000ULL, "CLONE_VFORK" ) _S(0x000008000ULL, "CLONE_PARENT" ) _S(0x000010000ULL, "CLONE_THREAD" ) _S(0x000020000ULL, "CLONE_NEWNS" ) _S(0x000040000ULL, "CLONE_SYSVSEM" ) _S(0x000080000ULL, "CLONE_SETTLS" ) _S(0x000100000ULL, "CLONE_PARENT_SETTID" ) _S(0x000200000ULL, "CLONE_CHILD_CLEARTID" ) _S(0x000400000ULL, "CLONE_DETACHED" ) _S(0x000800000ULL, "CLONE_UNTRACED" ) _S(0x001000000ULL, "CLONE_CHILD_SETTID" ) _S(0x002000000ULL, "CLONE_STOPPED" ) _S(0x004000000ULL, "CLONE_NEWUTS" ) _S(0x008000000ULL, "CLONE_NEWIPC" ) _S(0x010000000ULL, "CLONE_NEWUSER" ) _S(0x020000000ULL, "CLONE_NEWPID" ) _S(0x040000000ULL, "CLONE_NEWNET" ) _S(0x080000000ULL, "CLONE_IO" ) _S(0x100000000ULL, "CLONE_CLEAR_SIGHAND") _S(0x200000000ULL, "CLONE_INTO_CGROUP") audit-userspace-4.0.5/auparse/data_buf.c000066400000000000000000000256501501761310600201770ustar00rootroot00000000000000/* data_buf.c -- * Copyright 2007,2011 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * John Dennis */ /* * gcc -DTEST -g data_buf.c -o data_buf * gcc -DTEST -g data_buf.c -o data_buf && valgrind --leak-check=yes ./data_buf */ /*****************************************************************************/ /******************************** Documentation ******************************/ /*****************************************************************************/ /*****************************************************************************/ /******************************* Include Files *******************************/ /*****************************************************************************/ #include #include #include // for memmove() #include #include #include #include "data_buf.h" /*****************************************************************************/ /****************************** Internal Defines *****************************/ /*****************************************************************************/ #ifndef MIN #define MIN(a,b) (((a)<=(b))?(a):(b)) #endif #ifndef MAX #define MAX(a,b) (((a)>=(b))?(a):(b)) #endif //#define DEBUG 1 #ifdef DEBUG #define DATABUF_VALIDATE(db) \ { \ if (db->alloc_ptr == NULL || db->alloc_size == 0) { \ assert(db->alloc_ptr == NULL); \ assert(db->alloc_size == 0); \ assert(db->len == 0); \ } else { \ assert(db->offset <= db->alloc_size); \ assert(db->len <= db->alloc_size); \ assert(db->offset+db->len <= db->alloc_size); \ } \ } #else #define DATABUF_VALIDATE(db) #endif /*****************************************************************************/ /************************** Internal Type Definitions ************************/ /*****************************************************************************/ /*****************************************************************************/ /********************** External Function Declarations *********************/ /*****************************************************************************/ /*****************************************************************************/ /********************** Internal Function Declarations *********************/ /*****************************************************************************/ static int databuf_shift_data_to_beginning(DataBuf *db); /*****************************************************************************/ /************************* External Global Variables ***********************/ /*****************************************************************************/ /*****************************************************************************/ /************************* Internal Global Variables ***********************/ /*****************************************************************************/ #ifdef DEBUG static int debug = 0; #endif /*****************************************************************************/ /**************************** Inline Functions *****************************/ /*****************************************************************************/ static inline char *databuf_end(const DataBuf *db) {return (db->alloc_ptr == NULL) ? NULL : db->alloc_ptr+db->offset+db->len;} static inline unsigned databuf_tail_size(const DataBuf *db) {return db->alloc_size - (db->offset+db->len);} static inline unsigned databuf_tail_available(DataBuf *db, size_t append_len) {return append_len <= databuf_tail_size(db);} /*****************************************************************************/ /*************************** Internal Functions ****************************/ /*****************************************************************************/ static int databuf_shift_data_to_beginning(DataBuf *db) { DATABUF_VALIDATE(db); if (db->flags & DATABUF_FLAG_PRESERVE_HEAD) return -1; if (databuf_beg(db) == NULL) return 1; if (db->offset) { memmove(db->alloc_ptr, databuf_beg(db), db->len); db->offset = 0; } DATABUF_VALIDATE(db); return 1; } /*****************************************************************************/ /**************************** Exported Functions ***************************/ /*****************************************************************************/ void databuf_print(const DataBuf *db, int print_data, char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fmt) { vprintf(fmt, ap); } printf("%salloc_size=%zu alloc_ptr=%p offset=%zu beg=%p len=%zu max_len=%zu flags=[", fmt?" ":"", db->alloc_size, db->alloc_ptr, db->offset, databuf_beg(db), db->len, db->max_len); if (db->flags & DATABUF_FLAG_PRESERVE_HEAD) printf("PRESERVE_HEAD "); printf("]"); if (print_data) { printf(" ["); fwrite(databuf_beg(db), 1, db->len, stdout); printf("]"); } printf("\n"); va_end(ap); } int databuf_init(DataBuf *db, size_t size, unsigned flags) { db->alloc_ptr = NULL; db->alloc_size = 0; db->offset = 0; db->len = 0; db->max_len = 0; db->flags = flags; if (size) { if ((db->alloc_ptr = malloc(size))) { db->alloc_size = size; return 1; } else { return -1; } } return 1; } void databuf_free(DataBuf *db) { DATABUF_VALIDATE(db); if (db->alloc_ptr != NULL) { free(db->alloc_ptr); } db->alloc_ptr = NULL; db->alloc_size = 0; db->offset = 0; db->len = 0; db->max_len = 0; DATABUF_VALIDATE(db); } int databuf_append(DataBuf *db, const char *src, size_t src_size) { size_t new_size; DATABUF_VALIDATE(db); if (src == NULL || src_size == 0) return 0; new_size = db->len+src_size; #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_append() size=%zd", src_size); #endif if ((new_size > db->alloc_size) || ((db->flags & DATABUF_FLAG_PRESERVE_HEAD) && !databuf_tail_available(db, src_size))) { /* not enough room, we must realloc */ void *new_alloc; databuf_shift_data_to_beginning(db); if ((new_alloc = realloc(db->alloc_ptr, new_size))) { db->alloc_ptr = new_alloc; db->alloc_size = new_size; } else { return -1; /* realloc failed */ } } else { /* we can fit within current allocation, but can we append? */ if (!databuf_tail_available(db, src_size)) { /* we can't append in place, must create room at tail by shifting data forward to the beginning of the allocation block */ databuf_shift_data_to_beginning(db); } } #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_append() about to memmove()"); #endif /* pointers all set up and room available, move the data and update */ memmove(databuf_end(db), src, src_size); db->len = new_size; db->max_len = MAX(db->max_len, new_size); #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_append() conclusion"); #endif DATABUF_VALIDATE(db); return 1; } int databuf_replace(DataBuf *db, const char *src, size_t src_size) { DATABUF_VALIDATE(db); if (src == NULL || src_size == 0) return 0; db->len = 0; return databuf_append(db, src, src_size); } int databuf_advance(DataBuf *db, size_t advance) { size_t actual_advance; DATABUF_VALIDATE(db); #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_advance() enter, advance=%zd", advance); #endif actual_advance = MIN(advance, db->len); db->offset += actual_advance; db->len -= actual_advance; #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_advance() leave, actual_advance=%zd", actual_advance); #endif DATABUF_VALIDATE(db); if (advance == actual_advance) { return 1; } else { errno = ESPIPE; // Illegal seek return -1; } } int databuf_reset(DataBuf *db) { #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_reset() entry"); #endif if (!(db->flags & DATABUF_FLAG_PRESERVE_HEAD)) return -1; db->offset = 0; db->len = MIN(db->alloc_size, db->max_len); #ifdef DEBUG if (debug) databuf_print(db, 1, "databuf_reset() exit"); #endif return 1; } /*****************************************************************************/ /******************************* Test Program ******************************/ /*****************************************************************************/ #ifdef TEST static char *make_data(size_t size, const char *fill) { int n=0; char *data = malloc(size); if (data == NULL) { fprintf(stderr, "ERROR: make_data malloc failed\n"); exit(1); } n += snprintf(data, size, "%d", size); while (n < size) { n += snprintf(data+n, size-n, "%s", fill); } return data; } int main(int argc, char **argv) { size_t size = 0; DataBuf buf; char *data; int rc; rc = databuf_init(&buf, size, 0); assert(rc); databuf_print(&buf, 1, "after init size=%d", size); databuf_free(&buf); #if 0 assert(databuf_init(&buf, size, 0)); databuf_print(&buf, 1, "after init size=%d", size); size = 8; data = make_data(size, "a"); assert(databuf_append(&buf, data, size)); databuf_print(&buf, 1, "after append size=%d", size); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); assert(databuf_advance(&buf, 4)); databuf_print(&buf, 1, "after databuf_advance(%d", 4); size = 5; data = make_data(size, "b"); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); size = 7; data = make_data(size, "c"); assert(databuf_append(&buf, data, size)); free(data); databuf_print(&buf, 1, "after append size=%d", size); databuf_free(&buf); #endif exit(0); } #endif audit-userspace-4.0.5/auparse/data_buf.h000066400000000000000000000063041501761310600201770ustar00rootroot00000000000000/* data_buf.h -- * Copyright 2007 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * John Dennis */ #ifndef DATA_BUF_HEADER #define DATA_BUF_HEADER /*****************************************************************************/ /******************************* Include Files *******************************/ /*****************************************************************************/ #include "config.h" #include "private.h" /*****************************************************************************/ /*********************************** Defines *********************************/ /*****************************************************************************/ #define DATABUF_FLAG_PRESERVE_HEAD (1 << 0) /*****************************************************************************/ /******************************* Type Definitions ****************************/ /*****************************************************************************/ typedef struct Databuf { unsigned flags; size_t alloc_size; char *alloc_ptr; size_t offset; size_t len; size_t max_len; } DataBuf; /*****************************************************************************/ /************************* External Global Variables ***********************/ /*****************************************************************************/ /*****************************************************************************/ /***************************** Inline Functions ****************************/ /*****************************************************************************/ static inline char *databuf_beg(const DataBuf *db) {return (db->alloc_ptr == NULL) ? NULL : db->alloc_ptr+db->offset;} /*****************************************************************************/ /**************************** Exported Functions ***************************/ /*****************************************************************************/ AUDIT_HIDDEN_START void databuf_print(const DataBuf *db, int print_data, char *fmt, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 3, 4))); #else ; #endif int databuf_init(DataBuf *db, size_t size, unsigned flags); void databuf_free(DataBuf *db); int databuf_append(DataBuf *db, const char *src, size_t src_size); int databuf_replace(DataBuf *db, const char *src, size_t src_size); int databuf_advance(DataBuf *db, size_t advance); int databuf_reset(DataBuf *db); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/ellist.c000066400000000000000000000254311501761310600177230ustar00rootroot00000000000000/* * ellist.c - Minimal linked list library * Copyright (c) 2006-08,2014,2016-17,2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include #include #include #include #include "libaudit.h" #include "ellist.h" #include "interpret.h" #include "common.h" static const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 }; void aup_list_create(event_list_t *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; l->e.milli = 0L; l->e.sec = 0L; l->e.serial = 0L; l->e.host = NULL; l->cwd = NULL; } static void aup_list_last(event_list_t *l) { register rnode* node; if (l->head == NULL) return; node = l->head; while (node->next) node = node->next; l->cur = node; } rnode *aup_list_next(event_list_t *l) { if (l->cur) l->cur = l->cur->next; return l->cur; } /* * * This function does encoding of "untrusted" names just like the kernel * */ static char *_audit_c2x(char *final, const char *buf, unsigned int size) { unsigned int i; char *ptr = final; const char *hex = "0123456789ABCDEF"; for (i=0; i>4]; /* Upper nibble */ *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */ } *ptr = 0; return final; } static char *escape(const char *tmp) { char *name; const unsigned char *p = (unsigned char *)tmp; while (*p) { if (*p == '"' || *p < 0x21 || *p > 0x7e) { int len = strlen(tmp); name = malloc((2*len)+1); return _audit_c2x(name, tmp, len); } p++; } if (asprintf(&name, "\"%s\"", tmp) < 0) name = NULL; return name; } /* This function does the heavy duty work of splitting a record into * its little tiny pieces */ static int parse_up_record(rnode* r) { char *ptr, *buf, *saved=NULL; unsigned int offset = 0, len; // Potentially cut the record in two ptr = strchr(r->record, AUDIT_INTERP_SEPARATOR); if (ptr) { *ptr = 0; ptr++; } r->interp = ptr; // Rather than call strndup, we will do it ourselves to reduce // the number of interactions across the record. // len includes the string terminator. len = strlen(r->record) + 1; r->nv.record = buf = malloc(len); if (r->nv.record == NULL) return -1; memcpy(r->nv.record, r->record, len); r->nv.end = r->nv.record + len; ptr = audit_strsplit_r(buf, &saved); // If no fields we have fuzzer induced problems, leave if (ptr == NULL) { free(buf); r->nv.record = NULL; return -1; } do { // If there's an '=' sign, its a keeper nvnode n; char *val = strchr(ptr, '='); if (val) { int vlen; // If name is 'msg=audit' throw it away if (*ptr == 'm' && strncmp(ptr, "msg=", 4) == 0) { if (ptr[4] == 'a') continue; // If name is 'msg='' chop off and see // if there is still a = in the string. else if (ptr[4] == '\'') { ptr += 5; val = strchr(ptr, '='); if (val == NULL) continue; } } // Split the string *val = 0; val++; // Remove beginning cruft of name if (*ptr == '(') ptr++; n.name = ptr; n.val = val; // Remove trailing punctuation vlen = strlen(n.val); // Check for invalid val if (!vlen) continue; if (n.val[vlen-1] == ':') { n.val[vlen-1] = 0; vlen--; } if (n.val[vlen-1] == ',') { n.val[vlen-1] = 0; vlen--; } if (n.val[vlen-1] == '\'') { n.val[vlen-1] = 0; vlen--; } if (n.val[vlen-1] == ')') { if (strcmp(n.val, "(none)") && strcmp(n.val, "(null)")) { n.val[vlen-1] = 0; vlen--; } } // Make virtual keys or just store it if (strcmp(n.name, "key") == 0 && *n.val != '(') { if (*n.val == '"') { // This is a normal single key. n.name = strdup("key"); char *t = strdup(n.val); n.val = t; if (nvlist_append(&r->nv, &n)) { free(n.name); free(n.val); continue; } } else { // Virtual keys char *key, *ptr2, *saved2; key = (char *)au_unescape(n.val); if (key == NULL) { n.name = strdup("key"); n.val = NULL; // Malformed key - save as is if (nvlist_append(&r->nv, &n)) { free(n.name); free(n.val); } continue; } ptr2 = strtok_r(key, key_sep, &saved2); while (ptr2) { n.name = strdup("key"); n.val = escape(ptr2); if (nvlist_append(&r->nv, &n)) { free(n.name); free(n.val); } ptr2 = strtok_r(NULL, key_sep, &saved2); } free(key); } continue; } else { if (strcmp(n.name, "key") == 0) { // This is a null key n.name = strdup("key"); char *t = strdup(n.val); n.val = t; if (nvlist_append(&r->nv, &n)) { free(n.name); free(n.val); continue; } } else // everything not a key nvlist_append(&r->nv, &n); } // Do some info gathering for use later if (r->nv.cnt == 1 && strcmp(n.name, "node") == 0) offset = 1; // if node, some positions changes // This has to account for seccomp records else if (r->nv.cnt == (1 + offset) && strcmp(n.name, "type") == 0) { r->type = audit_name_to_msg_type(n.val); if (r->type == AUDIT_URINGOP) r->machine = MACH_IO_URING; // This has to account for seccomp records } else if ((r->nv.cnt == (2 + offset) || r->nv.cnt == (11 + offset)) && strcmp(n.name, "arch")== 0){ unsigned int ival; errno = 0; ival = strtoul(n.val, NULL, 16); if (errno) r->machine = -2; else r->machine = audit_elf_to_machine(ival); } else if ((r->nv.cnt == (3 + offset) || r->nv.cnt == (12 + offset)) && strcmp(n.name, "syscall") == 0){ errno = 0; r->syscall = strtoul(n.val, NULL, 10); if (errno) r->syscall = -1; } else if (r->nv.cnt == (2 + offset) && strcmp(n.name, "uring_op") == 0) { errno = 0; r->syscall = strtoul(n.val, NULL, 10); if (errno) r->syscall = -1; } else if (r->nv.cnt == (6 + offset) && strcmp(n.name, "a0") == 0){ errno = 0; r->a0 = strtoull(n.val, NULL, 16); if (errno) r->a0 = -1LL; } else if (r->nv.cnt == (7 + offset) && strcmp(n.name, "a1") == 0){ errno = 0; r->a1 = strtoull(n.val, NULL, 16); if (errno) r->a1 = -1LL; } else if (r->type == AUDIT_CWD) { // most common fuzzing hit: duplicate cwds if (strcmp(n.name, "cwd") == 0 && !r->cwd) r->cwd = strdup(n.val); } } else if (r->type == AUDIT_AVC || r->type == AUDIT_USER_AVC) { // We special case these 2 fields because selinux // avc messages do not label these fields. n.name = NULL; if (nvlist_get_cnt(&r->nv) == (1 + offset)) { // skip over 'avc:' if (strncmp(ptr, "avc", 3) == 0) continue; n.name = strdup("seresult"); } else if (nvlist_get_cnt(&r->nv) == (2 + offset)) { // skip over open brace if (*ptr == '{') { int total = 0, clen; char tmpctx[256], *to; tmpctx[0] = 0; to = tmpctx; ptr = audit_strsplit_r(NULL, &saved); while (ptr && *ptr != '}') { clen = strlen(ptr); if ((clen+1) >= (256-total)) { if (nvlist_get_cnt(&r->nv) == 0) free(buf); return -1; } if (tmpctx[0]) { to = stpcpy(to, ","); total++; } to = stpcpy(to, ptr); total += clen; ptr = audit_strsplit_r(NULL, &saved); } n.name = strdup("seperms"); n.val = strdup(tmpctx); if (nvlist_append(&r->nv, &n)) { free(n.name); free(n.val); } continue; } } else continue; n.val = ptr; nvlist_append(&r->nv, &n); } } while((ptr = audit_strsplit_r(NULL, &saved))); // If for some reason it was useless, delete buf if (r->nv.cnt == 0) { free(buf); r->nv.record = NULL; r->nv.end = NULL; free((void *)r->cwd); r->cwd = NULL; } r->nv.cur = 0; // reset to beginning return 0; } int aup_list_append(event_list_t *l, char *record, int list_idx, unsigned int line_number) { int rc; rnode* r; if (record == NULL) return -1; // First step is build rnode r = malloc(sizeof(rnode)); if (r == NULL) return -1; r->record = record; r->interp = NULL; r->cwd = NULL; r->type = 0; r->a0 = 0LL; r->a1 = 0LL; r->machine = -1; r->syscall = -1; r->item = l->cnt; r->list_idx = list_idx; r->line_number = line_number; r->next = NULL; nvlist_create(&r->nv); // if we are at top, fix this up if (l->head == NULL) l->head = r; else { // Otherwise add pointer to newnode aup_list_last(l); l->cur->next = r; } // make newnode current l->cur = r; l->cnt++; // Then parse the record up into nvlist rc = parse_up_record(r); if (r->nv.cnt == 0) // This is fuzzer induced, return an error. rc = -1; if (r->cwd) { // Should never be 2 cwd records unless log is corrupted free((void *)l->cwd); l->cwd = r->cwd; } return rc; } void aup_list_clear(event_list_t* l) { rnode* nextnode; register rnode* current; if (l == NULL) return; current = l->head; while (current) { nextnode=current->next; nvlist_clear(¤t->nv, 1); free(current->record); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; l->e.milli = 0L; l->e.sec = 0L; l->e.serial = 0L; free((char *)l->e.host); l->e.host = NULL; free((void *)l->cwd); } /*int aup_list_get_event(event_list_t* l, au_event_t *e) { if (l == NULL || e == NULL) return 0; e->sec = l->e.sec; e->milli = l->e.milli; e->serial = l->e.serial; if (l->e.host) e->host = strdup(l->e.host); else e->host = NULL; return 1; } */ int aup_list_set_event(event_list_t* l, au_event_t *e) { if (l == NULL || e == NULL) return 0; l->e.sec = e->sec; l->e.milli = e->milli; l->e.serial = e->serial; l->e.host = e->host; // Take custody of the memory e->host = NULL; return 1; } rnode *aup_list_goto_rec(event_list_t *l, int i) { register rnode* node; node = l->head; /* start at the beginning */ while (node) { if (node->item == i) { l->cur = node; return node; } else node = node->next; } return NULL; } int aup_list_first_field(const event_list_t *l) { if (l && l->cur) { nvlist_first(&l->cur->nv); return 1; } else return 0; } audit-userspace-4.0.5/auparse/ellist.h000066400000000000000000000042261501761310600177270ustar00rootroot00000000000000/* * ellist.h - Header file for ellist.c * Copyright (c) 2006-07,2017,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef ELLIST_HEADER #define ELLIST_HEADER #include "config.h" #include "private.h" #include "auparse-defs.h" #include #include "nvlist.h" /* This is the record linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { rnode *head; // List head rnode *cur; // Pointer to current node unsigned int cnt; // How many items in this list // Data we add as 1 per event au_event_t e; // event - time & serial number const char *cwd; // cwd used for realpath conversion } event_list_t; static inline unsigned int aup_list_get_cnt(const event_list_t *l) { return l ? l->cnt : 0; } static inline void aup_list_first(event_list_t *l) { l->cur = l->head; } static inline rnode *aup_list_get_cur(const event_list_t *l) { return l ? l->cur : NULL; } AUDIT_HIDDEN_START void aup_list_create(event_list_t *l); void aup_list_clear(event_list_t* l); rnode *aup_list_next(event_list_t *l); int aup_list_append(event_list_t *l, char *record, int list_idx, unsigned int line_number); //int aup_list_get_event(event_list_t* l, au_event_t *e); int aup_list_set_event(event_list_t* l, au_event_t *e); /* Seek to a specific record number */ rnode *aup_list_goto_rec(event_list_t *l, int i); int aup_list_first_field(const event_list_t *l); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/epoll_ctl.h000066400000000000000000000020021501761310600203760ustar00rootroot00000000000000/* epoll_ctl.h -- * Copyright 2008,2012,2014 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/eventpoll.h */ _S(1, "EPOLL_CTL_ADD" ) _S(2, "EPOLL_CTL_DEL" ) _S(3, "EPOLL_CTL_MOD" ) audit-userspace-4.0.5/auparse/expression-design.txt000066400000000000000000000117501501761310600224710ustar00rootroot00000000000000This is a description of the expression syntax. LEXICAL STRUCTURE White space (ASCII space, tab and new-line characters) between tokens is ignored. The following tokens are recognized: Punctuation ( ) \ Logical operators ! && || Comparison operators < <= == > >= !== i= i!= r= r!= Unquoted strings Any non-empty sequence of ASCII letters, digits, and the _ symbol. Quoted strings A sequence of characters surrounded by the " quotes. The \ character starts an escape sequence. The only defined escape sequences are \\ and \". The semantics of other escape sequences is undefined. Anywhere an unquoted string is valid, a quoted string is valid as well, and vice versa. In particular, field names may be specified using quoted strings, and field values may be specified using unquoted strings. EXPRESSION SYNTAX The primary expression has the following form: field comparison-operator value field is either a string, which specifies the first field with that name within the current audit record, or the \ escape character fol- lowed by a string, which specifies a virtual field with the specified name (virtual fields are defined in a later section). field is a string. operator specifies the comparison to perform r= r!= Get the "raw" string of field, and compare it to value. For fields in audit records, the "raw" string is the exact string stored in the audit record (with all escaping and unprintable character encoding left alone); applications can read the "raw" string using auparse get field str(3). Each virtual field may define a "raw" string. If field is not present or does not define a "raw" string, the result of the comparison is false (regardless of the operator). i= i!= Get the "interpreted" string of field, and compare it to value. For fields in audit records, the "interpreted" string is an "user-readable" interpretation of the field value; applications can read the "interpreted" string using auparse inter- pret field(3). Each virtual field may define an "interpreted" string. If field is not present or does not define an "inter- preted" string, the result of the comparison is false (regard- less of the operator). < <= == > >= !== Evaluate the "value" of field, and compare it to value. A "value" may be defined for any field or virtual field, but no "value" is currently defined for any audit record field. The rules of parsing value for comparing it with the "value" of field are specific for each field. If field is not present, the result of the comparison is false (regardless of the operator). If field does not define a "value", an error is reported when parsing the expression. If E1 and E2 are valid expressions, then ! E1, E1 && E2, and E1 || E2 are valid expressions as well, with the usual C semantics and evalua- tion priorities. Note that ! field op value is interpreted as !(field op value), not as (!field) op value. VIRTUAL FIELDS The following virtual fields are defined: \timestamp The value is the timestamp of the current event. value must have the ts:seconds.milli format, where seconds and milli are decimal numbers specifying the seconds and milliseconds part of the timestamp, respectively. \record_type The value is the type of the current record. value is either the record type name, or a decimal number specifying the type. SEMANTICS The expression as a whole applies to a single record. The expression is true for a specified event if it is true for any record associated with the event. EXAMPLES As a demonstration of the semantics of handling missing fields, the following expression is true if field is present: (field r= "") || (field r!= "") and the same expression surrounded by !( and ) is true if field is not present. FUTURE DIRECTIONS New escape sequences for quoted strings may be defined. For currently defined virtual fields that do not define a "raw" or "interpreted" string, the definition may be added. Therefore, donât rely on the fact that comparing the "raw" or "interpreted" string of the field with any value is false. New formats of value constants for the \timestamp virtual field may be added. audit-userspace-4.0.5/auparse/expression.c000066400000000000000000000665031501761310600206330ustar00rootroot00000000000000/* * expression.c - Expression parsing and handling * Copyright (C) 2008,2014,2016 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač * Steve Grubb extended timestamp */ #include #include #include #include #include #include "expression.h" #include "interpret.h" /* Utilities */ /* Free EXPR and all its subexpressions. */ void expr_free(struct expr *expr) { switch (expr->op) { case EO_NOT: expr_free(expr->v.sub[0]); break; case EO_AND: case EO_OR: expr_free(expr->v.sub[0]); expr_free(expr->v.sub[1]); break; case EO_RAW_EQ: case EO_RAW_NE: case EO_INTERPRETED_EQ: case EO_INTERPRETED_NE: case EO_VALUE_EQ: case EO_VALUE_NE: case EO_VALUE_LT: case EO_VALUE_LE: case EO_VALUE_GT: case EO_VALUE_GE: if (expr->virtual_field == 0) free(expr->v.p.field.name); if (expr->precomputed_value == 0) free(expr->v.p.value.string); break; case EO_FIELD_EXISTS: assert(expr->virtual_field == 0); free(expr->v.p.field.name); break; case EO_REGEXP_MATCHES: regfree(expr->v.regexp); free(expr->v.regexp); break; default: abort(); } free(expr); } /* Expression parsing. */ /* The formal grammar: start: or-expression or-expression: and-expression or-expression: or-expression || and-expression and-expression: primary-expression and-expression: and-expression && primary-expression primary-expression: ! primary-expression primary-expression: ( or-expression ) primary-expression: comparison-expression comparison-expression: field op value comparison-expression: field-escape "regexp" regexp-value field: string field: field-escape string value: string regexp-value: string regexp-value: regexp */ /* Token types */ enum token_type { /* EO_* */ T_LEFT_PAREN = NUM_EO_VALUES, T_RIGHT_PAREN, T_STRING, T_REGEXP, T_FIELD_ESCAPE, T_UNKNOWN, T_EOF }; /* Expression parsing status */ struct parsing { char **error; /* Error message destination. */ enum token_type token; const char *token_start; /* Original "src" value */ int token_len; /* int because it must be usable in %.*s */ char *token_value; /* Non-NULL only for T_STRING, until used */ const char *src; /* Expression source, after the current token */ }; static struct expr *parse_or(struct parsing *p); /* Allocate SIZE bytes. On error, return NULL and try to set *P->ERROR. */ static void * parser_malloc(struct parsing *p, size_t size) { void *res; res = malloc(size); if (res) return res; *p->error = strdup("Out of memory"); return NULL; } /* Reallocate PTR to SIZE bytes. On error, free(PTR), return NULL and try to set *P->ERROR. NOTE: realloc() does not free(PTR), this function does. */ static void * parser_realloc(struct parsing *p, void *ptr, size_t size) { void *res; if (size == 0) { free(ptr); return NULL; } res = realloc(ptr, size); if (res) return res; free(ptr); *p->error = strdup("Out of memory"); return NULL; } /* Discard P->token_value, if any, and parse the next token in P->src. On success, return 0. On error, set *P->ERROR to an error string (for free()) or NULL, and return -1. */ static int lex(struct parsing *p) { free(p->token_value); p->token_value = NULL; while (*p->src == ' ' || *p->src == '\t' || *p->src == '\n') p->src++; p->token_start = p->src; switch (*p->src) { case '\0': p->token = T_EOF; break; case '!': p->src++; if (*p->src == '=' && p->src[1] == '=') { p->src += 2; p->token = EO_VALUE_NE; break; } p->token = EO_NOT; break; case '"': case '/': { char *buf, delimiter; size_t dest, buf_size; delimiter = *p->src; buf_size = 8; buf = parser_malloc(p, buf_size); if (buf == NULL) return -1; p->src++; dest = 0; while (*p->src != delimiter) { if (*p->src == '\0') { *p->error = strdup("Terminating delimiter " "missing"); free(buf); return -1; } if (*p->src == '\\') { p->src++; if (*p->src != '\\' && *p->src != delimiter) { if (asprintf(p->error, "Unknown escape " "sequence ``\\%c''", *p->src) < 0) *p->error = NULL; free(buf); return -1; } } /* +1: make sure there is space for the terminating NUL. */ if (dest + 1 >= buf_size) { if (buf_size > SIZE_MAX / 2) { *p->error = strdup("Delimited string " "too long"); free(buf); return -1; } buf_size *= 2; buf = parser_realloc(p, buf, buf_size); if (buf == NULL) { *p->error = strdup("Out of memory"); return -1; } } buf[dest] = *p->src; dest++; p->src++; } p->src++; buf[dest] = '\0'; p->token_value = parser_realloc(p, buf, dest + 1); if (p->token_value == NULL) return -1; p->token = delimiter == '/' ? T_REGEXP : T_STRING; break; } case '&': p->src++; if (*p->src == '&') { p->src++; p->token = EO_AND; break; } p->token = T_UNKNOWN; break; case '(': p->src++; p->token = T_LEFT_PAREN; break; case ')': p->src++; p->token = T_RIGHT_PAREN; break; case '<': p->src++; if (*p->src == '=') { p->src++; p->token = EO_VALUE_LE; break; } p->token = EO_VALUE_LT; break; case '=': p->src++; if (*p->src == '=') { p->src++; p->token = EO_VALUE_EQ; break; } p->token = T_UNKNOWN; break; case '>': p->src++; if (*p->src == '=') { p->src++; p->token = EO_VALUE_GE; break; } p->token = EO_VALUE_GT; break; case '\\': p->src++; p->token = T_FIELD_ESCAPE; break; case '|': p->src++; if (*p->src == '|') { p->src++; p->token = EO_OR; break; } p->token = T_UNKNOWN; break; case 'i': if (p->src[1] == '=') { p->src += 2; p->token = EO_INTERPRETED_EQ; break; } else if (p->src[1] == '!' && p->src[2] == '=') { p->src += 3; p->token = EO_INTERPRETED_NE; break; } goto unquoted_string; case 'r': if (p->src[1] == '=') { p->src += 2; p->token = EO_RAW_EQ; break; } else if (p->src[1] == '!' && p->src[2] == '=') { p->src += 3; p->token = EO_RAW_NE; break; } goto unquoted_string; default: /* This assumes ASCII */ assert ('Z' == 'A' + 25 && 'z' == 'a' + 25); #define IS_UNQUOTED_STRING_CHAR(C) \ (((C) >= 'a' && (C) <= 'z') \ || ((C) >= 'A' && (C) <= 'Z') \ || ((C) >= '0' && (C) <= '9') \ || (C) == '_' || (C) == '-') if (IS_UNQUOTED_STRING_CHAR(*p->src)) { size_t len; unquoted_string: do p->src++; while (IS_UNQUOTED_STRING_CHAR(*p->src)); len = p->src - p->token_start; p->token_value = parser_malloc(p, len + 1); if (p->token_value == NULL) return -1; memcpy(p->token_value, p->token_start, len); p->token_value[len] = '\0'; p->token = T_STRING; break; } p->src++; p->token = T_UNKNOWN; break; } if (p->src - p->token_start > INT_MAX) { *p->error = strdup("Token too long"); return -1; } p->token_len = p->src - p->token_start; return 0; } /* Parse an escaped field NAME to DEST. Return 0 on success, -1 if NAME is unknown. */ static int parse_escaped_field_name(enum field_id *dest, const char *name) { if (strcmp(name, "timestamp") == 0) *dest = EF_TIMESTAMP; else if (strcmp(name, "record_type") == 0) *dest = EF_RECORD_TYPE; else if (strcmp(name, "timestamp_ex") == 0) *dest = EF_TIMESTAMP_EX; else return -1; return 0; } /* Parse a \timestamp field value in P->token_value to DEST. On success, return 0. On error, set *P->ERROR to an error string (for free()) or NULL, and return -1. */ static int parse_timestamp_value(struct expr *dest, struct parsing *p) { intmax_t sec; assert(p->token == T_STRING); /* * On a timestamp field we will do all the parsing ourselves * rather than use lex(). At the end we will move the internal cursor. */ if (sscanf(p->token_start, "ts:%jd.%u:%u", &sec, &dest->v.p.value.timestamp_ex.milli, &dest->v.p.value.timestamp_ex.serial) != 3) { if (sscanf(p->token_start, "ts:%jd.%u", &sec, &dest->v.p.value.timestamp.milli) != 2) { if (asprintf(p->error, "Invalid timestamp value `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; return -1; } } /* Move the cursor past what we parsed. */ size_t num = strspn(p->token_start, "ts:0123456789."); p->src = p->token_start + num; /* FIXME: validate milli */ dest->v.p.value.timestamp.sec = sec; if (dest->v.p.value.timestamp.sec != sec) { if (asprintf(p->error, "Timestamp overflow in `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; return -1; } dest->precomputed_value = 1; return 0; } /* Parse a \record_type field value in P->token_value to DEST. On success, return 0. On error, set *P->ERROR to an error string (for free()) or NULL, and return -1. */ static int parse_record_type_value(struct expr *dest, struct parsing *p) { int type; assert(p->token == T_STRING); type = audit_name_to_msg_type(p->token_value); if (type < 0) { if (asprintf(p->error, "Invalid record type `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; return -1; } dest->v.p.value.int_value = type; dest->precomputed_value = 1; return 0; } /* Parse a uid/gid field value in P->token_value to DEST. On success, return 0. On error, set *P->ERROR to an error string (for free()) or NULL, and return -1. */ static int parse_unsigned_value(struct expr *dest, struct parsing *p) { uint32_t val; assert(p->token == T_STRING); errno = 0; val = strtoul(p->token_value, NULL, 10); if (errno) { if (asprintf(p->error, "Error converting number `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; return -1; } dest->v.p.unsigned_val = val; dest->precomputed_value = 1; return 0; } /* Parse a virtual field value in P->token_value to DEST. On success, return 0. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static int parse_virtual_field_value(struct expr *dest, struct parsing *p) { switch (dest->v.p.field.id) { case EF_TIMESTAMP: return parse_timestamp_value(dest, p); case EF_RECORD_TYPE: return parse_record_type_value(dest, p); case EF_TIMESTAMP_EX: return parse_timestamp_value(dest, p); default: abort(); } } /* Parse a \regexp comparison-expression string in *P, with \regexp parsed. Use or free EXPR. On success, return the parsed comparison-expression. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static struct expr * parse_comparison_regexp(struct parsing *p, struct expr *res) { int err; if (lex(p) != 0) goto err_res; if (p->token != T_STRING && p->token != T_REGEXP) { if (asprintf(p->error, "Regexp expected, got `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_res; } res->v.regexp = parser_malloc(p, sizeof(*res->v.regexp)); if (res->v.regexp == NULL) goto err_res; err = regcomp(res->v.regexp, p->token_value, REG_EXTENDED | REG_NOSUB); if (err != 0) { size_t err_size; char *err_msg; err_size = regerror(err, res->v.regexp, NULL, 0); err_msg = parser_malloc(p, err_size); if (err_msg == NULL) goto err_res_regexp; regerror(err, res->v.regexp, err_msg, err_size); if (asprintf(p->error, "Invalid regexp: %s", err_msg) < 0) *p->error = NULL; free(err_msg); goto err_res_regexp; } res->op = EO_REGEXP_MATCHES; if (lex(p) != 0) { expr_free(res); return NULL; } return res; err_res_regexp: free(res->v.regexp); err_res: free(res); return NULL; } /* Parse a comparison-expression string in *P. On success, return the parsed comparison-expression. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static struct expr * parse_comparison(struct parsing *p) { struct expr *res; res = parser_malloc(p, sizeof(*res)); if (res == NULL) return NULL; res->numeric_field = 0; if (p->token == T_FIELD_ESCAPE) { if (lex(p) != 0) goto err_res; if (p->token != T_STRING) { *p->error = strdup("Field name expected after field " "escape"); goto err_res; } if (strcmp(p->token_value, "regexp") == 0) return parse_comparison_regexp(p, res); res->virtual_field = 1; res->numeric_field = 1; if (parse_escaped_field_name(&res->v.p.field.id, p->token_value) != 0) { if (asprintf(p->error, "Unknown escaped field name `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_res; } } else { assert(p->token == T_STRING); res->virtual_field = 0; res->v.p.field.name = p->token_value; int type = lookup_type(p->token_value); if (type == AUPARSE_TYPE_UID || type == AUPARSE_TYPE_GID) res->numeric_field = 1; p->token_value = NULL; } if (lex(p) != 0) goto err_field; switch (p->token) { case EO_RAW_EQ: case EO_RAW_NE: case EO_INTERPRETED_EQ: case EO_INTERPRETED_NE: res->op = p->token; if (lex(p) != 0) goto err_field; if (p->token != T_STRING) { if (asprintf(p->error, "Value expected, got `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_field; } res->precomputed_value = 0; res->v.p.value.string = p->token_value; p->token_value = NULL; if (lex(p) != 0) { expr_free(res); return NULL; } break; case EO_VALUE_EQ: case EO_VALUE_NE: case EO_VALUE_LT: case EO_VALUE_LE: case EO_VALUE_GT: case EO_VALUE_GE: res->op = p->token; if (lex(p) != 0) goto err_field; if (p->token != T_STRING) { if (asprintf(p->error, "Value expected, got `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_field; } if (res->numeric_field == 0) { if (asprintf(p->error, "Field `%s' does not support " "value comparison", res->v.p.field.name) < 0) *p->error = NULL; goto err_field; } else { if (res->virtual_field) { if (parse_virtual_field_value(res, p) != 0) goto err_field; } else { if (parse_unsigned_value(res, p) != 0) goto err_field; } } if (lex(p) != 0) { expr_free(res); return NULL; } break; default: if (asprintf(p->error, "Operator expected, got `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_field; } return res; err_field: if (res->virtual_field == 0) free(res->v.p.field.name); err_res: free(res); return NULL; } /* Parse a primary-expression string in *P. On success, return the parsed primary-expression. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static struct expr * parse_primary(struct parsing *p) { struct expr *e; switch (p->token) { case EO_NOT: { struct expr *res; if (lex(p) != 0) return NULL; e = parse_primary(p); if (e == NULL) return NULL; res = parser_malloc(p, sizeof(*res)); if (res == NULL) goto err_e; res->op = EO_NOT; res->v.sub[0] = e; return res; } case T_LEFT_PAREN: { if (lex(p) != 0) return NULL; e = parse_or(p); if (e == NULL) return NULL; if (p->token != T_RIGHT_PAREN) { if (asprintf(p->error, "Right paren expected, got `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; goto err_e; } if (lex(p) != 0) goto err_e; return e; } case T_FIELD_ESCAPE: case T_STRING: return parse_comparison(p); default: if (asprintf(p->error, "Unexpected token `%.*s'", p->token_len, p->token_start) < 0) *p->error = NULL; return NULL; } err_e: expr_free(e); return NULL; } /* Parse an and-expression string in *P. On success, return the parsed and-expression. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static struct expr * parse_and(struct parsing *p) { struct expr *res; res = parse_primary(p); if (res == NULL) return NULL; while (p->token == EO_AND) { struct expr *e2, *e; if (lex(p) != 0) goto err_res; e2 = parse_primary(p); if (e2 == NULL) goto err_res; e = parser_malloc(p, sizeof(*e)); if (e == NULL) { expr_free(e2); goto err_res; } e->op = EO_AND; e->v.sub[0] = res; e->v.sub[1] = e2; res = e; } return res; err_res: expr_free(res); return NULL; } /* Parse an or-expression string in *P. On success, return the parsed or-expression. On error, set *P->ERROR to an error string (for free()) or NULL, and return NULL. */ static struct expr * parse_or(struct parsing *p) { struct expr *res; res = parse_and(p); if (res == NULL) return NULL; while (p->token == EO_OR) { struct expr *e2, *e; if (lex(p) != 0) goto err_res; e2 = parse_and(p); if (e2 == NULL) goto err_res; e = parser_malloc(p, sizeof(*e)); if (e == NULL) { expr_free(e2); goto err_res; } e->op = EO_OR; e->v.sub[0] = res; e->v.sub[1] = e2; res = e; } return res; err_res: expr_free(res); return NULL; } /* Parse STRING. On success, return the parsed expression tree. On error, set *ERROR to an error string (for free()) or NULL, and return NULL. (*ERROR == NULL is allowed to handle out-of-memory errors) */ struct expr * expr_parse(const char *string, char **error) { struct parsing p; struct expr *res; p.error = error; p.token_value = NULL; p.src = string; if (lex(&p) != 0) goto err; if (p.token == T_EOF) { *error = strdup("Empty expression"); goto err; } res = parse_or(&p); if (res != NULL && p.token != T_EOF) { expr_free(res); if (asprintf(error, "Unexpected trailing token `%.*s'", p.token_len, p.token_start) < 0) *error = NULL; goto err; } free(p.token_value); return res; err: free(p.token_value); return NULL; } /* Manual expression creation */ /* Create a comparison-expression for FIELD, OP and VALUE. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_comparison(const char *field, unsigned op, const char *value) { struct expr *res; res = calloc(sizeof(struct expr), 1); if (res == NULL) goto err; assert(op == EO_RAW_EQ || op == EO_RAW_NE || op == EO_INTERPRETED_EQ || op == EO_INTERPRETED_NE); res->op = op; res->virtual_field = 0; res->precomputed_value = 0; res->v.p.field.name = strdup(field); if (res->v.p.field.name == NULL) goto err_res; res->v.p.value.string = strdup(value); if (res->v.p.value.string == NULL) goto err_field; return res; err_field: free(res->v.p.field.name); err_res: free(res); err: return NULL; } /* Create an extended timestamp comparison-expression for with OP, SEC, MILLI, and SERIAL. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_timestamp_comparison_ex(unsigned op, time_t sec, unsigned milli, unsigned serial) { struct expr *res; res = calloc(sizeof(struct expr), 1); if (res == NULL) return NULL; assert(op == EO_VALUE_EQ || op == EO_VALUE_NE || op == EO_VALUE_LT || op == EO_VALUE_LE || op == EO_VALUE_GT || op == EO_VALUE_GE); res->op = op; res->virtual_field = 1; res->numeric_field = 1; res->v.p.field.id = EF_TIMESTAMP_EX; res->precomputed_value = 1; res->v.p.value.timestamp_ex.sec = sec; assert(milli < 1000); res->v.p.value.timestamp_ex.milli = milli; res->v.p.value.timestamp_ex.serial = serial; return res; } /* Create a timestamp comparison-expression for with OP, SEC, MILLI. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_timestamp_comparison(unsigned op, time_t sec, unsigned milli) { return expr_create_timestamp_comparison_ex(op, sec, milli, 0); } /* Create an EO_FIELD_EXISTS-expression for FIELD. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_field_exists(const char *field) { struct expr *res; res = calloc(sizeof(struct expr), 1); if (res == NULL) goto err; res->op = EO_FIELD_EXISTS; res->virtual_field = 0; res->v.p.field.name = strdup(field); if (res->v.p.field.name == NULL) goto err_res; return res; err_res: free(res); err: return NULL; } /* Create a \regexp expression for regexp comparison. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_regexp_expression(const char *regexp) { struct expr *res; res = calloc(sizeof(struct expr), 1); if (res == NULL) goto err; res->v.regexp = malloc(sizeof(*res->v.regexp)); if (res->v.regexp == NULL) goto err_res; if (regcomp(res->v.regexp, regexp, REG_EXTENDED | REG_NOSUB) != 0) { errno = EINVAL; goto err_res_regexp; } res->op = EO_REGEXP_MATCHES; return res; err_res_regexp: free(res->v.regexp); err_res: free(res); err: return NULL; } /* Create a binary expression for OP and subexpressions E1 and E2. On success, return the created expression. On error, set errno and return NULL. */ struct expr * expr_create_binary(unsigned op, struct expr *e1, struct expr *e2) { struct expr *res; res = calloc(sizeof(struct expr), 1); if (res == NULL) return NULL; assert(op == EO_AND || op ==EO_OR); res->op = op; res->v.sub[0] = e1; res->v.sub[1] = e2; return res; } /* Expression evaluation */ /* Return the "raw" value of the field in EXPR for RECORD in AU->le. Set *FREE_IT to 1 if the return value should free()'d. Return NULL on error. */ static char * eval_raw_value(rnode *record, const struct expr *expr, int *free_it) { if (expr->virtual_field == 0) { nvlist_first(&record->nv); if (nvlist_find_name(&record->nv, expr->v.p.field.name) == 0) return NULL; *free_it = 0; return (char *)nvlist_get_cur_val(&record->nv); } switch (expr->v.p.field.id) { case EF_TIMESTAMP: case EF_RECORD_TYPE: case EF_TIMESTAMP_EX: return NULL; default: abort(); } } /* Return the "int" value of the field in EXPR for RECORD in AU->le. Set valid to 1 if the return value is valid. Valid is set to 0 on error. */ static uint32_t eval_unsigned_value(rnode *record, const struct expr *expr, int *valid) { *valid = 0; if (expr->virtual_field == 0) { nvlist_first(&record->nv); if (nvlist_find_name(&record->nv, expr->v.p.field.name) == 0) return 0; const char *val = nvlist_get_cur_val(&record->nv); if (val) { uint32_t v = strtoul(val, NULL, 10); *valid = 1; return v; } } else abort(); return 0; } /* Return the "interpreted" value of the field in EXPR for RECORD in AU->le. Set *FREE_IT to 1 if the return value should free()'d. Return NULL on *error. */ static char * eval_interpreted_value(const auparse_state_t *au, rnode *record, const struct expr *expr, int *free_it) { if (expr->virtual_field == 0) { const char *res; nvlist_first(&record->nv); if (nvlist_find_name(&record->nv, expr->v.p.field.name) == 0) return NULL; *free_it = 0; res = nvlist_interp_cur_val(record, au->escape_mode); if (res == NULL) res = nvlist_get_cur_val(&record->nv); return (char *)res; } switch (expr->v.p.field.id) { case EF_TIMESTAMP: case EF_RECORD_TYPE: case EF_TIMESTAMP_EX: return NULL; default: abort(); } } static int compare_unsigned_values(uint32_t one, uint32_t two) { if (one < two) return -1; else if (one > two) return 1; return 0; } /* Return -1, 0, 1 depending on comparing the field in EXPR with RECORD in AU. Set *ERROR to 0 if OK, non-zero otherwise. */ static int compare_values(const auparse_state_t *au, const rnode *record, const struct expr *expr, int *error) { int res; if (expr->numeric_field == 0) { *error = 1; return 0; } switch (expr->v.p.field.id) { case EF_TIMESTAMP: if (au->le->e.sec < expr->v.p.value.timestamp.sec) res = -1; else if (au->le->e.sec > expr->v.p.value.timestamp.sec) res = 1; else if (au->le->e.milli < expr->v.p.value.timestamp.milli) res = -1; else if (au->le->e.milli > expr->v.p.value.timestamp.milli) res = 1; else res = 0; break; case EF_RECORD_TYPE: if (record->type < expr->v.p.value.int_value) res = -1; else if (record->type > expr->v.p.value.int_value) res = 1; else res = 0; break; case EF_TIMESTAMP_EX: if (au->le->e.sec < expr->v.p.value.timestamp.sec) res = -1; else if (au->le->e.sec > expr->v.p.value.timestamp.sec) res = 1; else if (au->le->e.milli < expr->v.p.value.timestamp.milli) res = -1; else if (au->le->e.milli > expr->v.p.value.timestamp.milli) res = 1; else if (au->le->e.serial < expr->v.p.value.timestamp_ex.serial) res = -1; else if (au->le->e.serial > expr->v.p.value.timestamp_ex.serial) res = 1; else res = 0; break; default: abort(); } *error = 0; return res; } /* Evaluate EXPR on RECORD in AU->le. Return 1 if EXPR is true, 0 if it false or if it fails. (No error reporting facility is provided; an invalid term is considered to be false; e.g. !invalid is true.) */ int expr_eval(auparse_state_t *au, rnode *record, const struct expr *expr) { int res; switch (expr->op) { case EO_NOT: res = !expr_eval(au, record, expr->v.sub[0]); break; case EO_AND: res = (expr_eval(au, record, expr->v.sub[0]) && expr_eval(au, record, expr->v.sub[1])); break; case EO_OR: res = (expr_eval(au, record, expr->v.sub[0]) || expr_eval(au, record, expr->v.sub[1])); break; case EO_RAW_EQ: case EO_RAW_NE: { int free_it, ne; char *value; value = eval_raw_value(record, expr, &free_it); if (value == NULL) return 0; assert(expr->precomputed_value == 0); ne = strcmp(expr->v.p.value.string, value); if (free_it != 0) free(value); res = expr->op == EO_RAW_EQ ? ne == 0 : ne != 0; break; } case EO_INTERPRETED_EQ: case EO_INTERPRETED_NE: { int free_it, ne; char *value; value = eval_interpreted_value(au, record, expr, &free_it); if (value == NULL) return 0; assert(expr->precomputed_value == 0); ne = strcmp(expr->v.p.value.string, value); if (free_it != 0) free(value); res = expr->op == EO_INTERPRETED_EQ ? ne == 0 : ne != 0; break; } case EO_VALUE_EQ: case EO_VALUE_NE: case EO_VALUE_LT: case EO_VALUE_LE: case EO_VALUE_GT: case EO_VALUE_GE: { int err = 0, cmp; if (expr->virtual_field == 0) { // UID & GID here int valid; uint32_t val = eval_unsigned_value(record,expr,&valid); if (valid == 0) return 0; cmp = compare_unsigned_values(val, expr->v.p.unsigned_val); } else // virtual fields here cmp = compare_values(au, record, expr, &err); if (err != 0) return 0; switch (expr->op) { case EO_VALUE_EQ: res = cmp == 0; break; case EO_VALUE_NE: res = cmp != 0; break; case EO_VALUE_LT: res = cmp < 0; break; case EO_VALUE_LE: res = cmp <= 0; break; case EO_VALUE_GT: res = cmp > 0; break; case EO_VALUE_GE: res = cmp >= 0; break; default: abort(); } } break; case EO_FIELD_EXISTS: assert(expr->virtual_field == 0); nvlist_first(&record->nv); res = nvlist_find_name(&record->nv, expr->v.p.field.name) != 0; break; case EO_REGEXP_MATCHES: res = regexec(expr->v.regexp, record->record, 0, NULL, 0) == 0; break; default: abort(); } return res; } audit-userspace-4.0.5/auparse/expression.h000066400000000000000000000106641501761310600206350ustar00rootroot00000000000000/* * expression.h - Expression parsing and handling * Copyright (C) 2008,2014 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač * Steve Grubb extended timestamp */ #ifndef EXPRESSION_H__ #define EXPRESSION_H__ #include #include #include "internal.h" enum { EO_NOT, /* Uses v.sub[0] */ EO_AND, EO_OR, /* Uses v.sub[0] and v.sub[1] */ /* All of the following use v.p */ EO_RAW_EQ, EO_RAW_NE, EO_INTERPRETED_EQ, EO_INTERPRETED_NE, EO_VALUE_EQ, EO_VALUE_NE, EO_VALUE_LT, EO_VALUE_LE, EO_VALUE_GT, EO_VALUE_GE, /* Uses v.p.field. Cannot be specified by an expression. */ EO_FIELD_EXISTS, EO_REGEXP_MATCHES, /* Uses v.regexp */ NUM_EO_VALUES, }; enum field_id { EF_TIMESTAMP, EF_RECORD_TYPE, EF_TIMESTAMP_EX }; struct expr { unsigned op : 8; /* EO_* */ unsigned virtual_field : 1; /* Can be non-zero only if virtual_field != 0 */ unsigned precomputed_value : 1; /* Decides if >= > < <= applies to field */ unsigned numeric_field : 1; unsigned started : 1; union { struct expr *sub[2]; struct { union { char *name; enum field_id id; /* If virtual_field != 0 */ } field; union { char *string; /* A member from the following is selected implicitly by field.id. */ struct { time_t sec; unsigned int milli; } timestamp; /* EF_TIMESTAMP */ struct { time_t sec; unsigned milli; unsigned serial; } timestamp_ex; /* EF_TIMESTAMP_EX */ int int_value; /* EF_RECORD_TYPE */ } value; uint32_t unsigned_val; /* UID & GID */ } p; regex_t *regexp; } v; }; AUDIT_HIDDEN_START /* Free EXPR and all its subexpressions. */ void expr_free(struct expr *expr); /* Parse STRING. On success, return the parsed expression tree. On error, set *ERROR to an error string (for free()) or NULL, and return NULL. (*ERROR == NULL is allowed to handle out-of-memory errors) */ struct expr *expr_parse(const char *string, char **error); /* Create a comparison-expression for FIELD, OP and VALUE. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_comparison(const char *field, unsigned op, const char *value); /* Create a timestamp comparison-expression for with OP, SEC, MILLI. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_timestamp_comparison(unsigned op, time_t sec, unsigned milli); /* Create an extended timestamp comparison-expression for with OP, SEC, MILLI, and SERIAL. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_timestamp_comparison_ex(unsigned op, time_t sec, unsigned milli, unsigned serial); /* Create an EO_FIELD_EXISTS-expression for FIELD. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_field_exists(const char *field); /* Create a \regexp expression for regexp comparison. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_regexp_expression(const char *regexp); /* Create a binary expression for OP and subexpressions E1 and E2. On success, return the created expression. On error, set errno and return NULL. */ struct expr *expr_create_binary(unsigned op, struct expr *e1, struct expr *e2); /* Evaluate EXPR on RECORD in AU->le. Return 1 if EXPR is true, 0 if it false or if it fails. (No error reporting facility is provided; an invalid term is considered to be false; e.g. !invalid is true.) */ int expr_eval(auparse_state_t *au, rnode *record, const struct expr *expr); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/famtab.h000066400000000000000000000036101501761310600176610ustar00rootroot00000000000000/* famtab.h -- * Copyright 2007,2012-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/linux/socket.h */ _S(AF_LOCAL, "local" ) _S(AF_INET, "inet" ) _S(AF_AX25, "ax25" ) _S(AF_IPX, "ipx" ) _S(AF_APPLETALK, "appletalk" ) _S(AF_NETROM, "netrom" ) _S(AF_BRIDGE, "bridge" ) _S(AF_ATMPVC, "atmpvc" ) _S(AF_X25, "x25" ) _S(AF_INET6, "inet6" ) _S(AF_ROSE, "rose" ) _S(AF_DECnet, "decnet" ) _S(AF_NETBEUI, "netbeui" ) _S(AF_SECURITY, "security" ) _S(AF_KEY, "key" ) _S(AF_NETLINK, "netlink" ) _S(AF_PACKET, "packet" ) _S(AF_ASH, "ash" ) _S(AF_ECONET, "econet" ) _S(AF_ATMSVC, "atmsvc" ) _S(AF_RDS, "rds" ) _S(AF_SNA, "sna" ) _S(AF_IRDA, "irda" ) _S(AF_PPPOX, "pppox" ) _S(AF_WANPIPE, "wanpipe" ) _S(AF_LLC, "llc" ) _S(AF_CAN, "can" ) _S(AF_TIPC, "tipc" ) _S(AF_BLUETOOTH, "bluetooth" ) _S(AF_IUCV, "iucv" ) _S(AF_RXRPC, "rxrpc" ) _S(AF_ISDN, "isdn" ) _S(AF_PHONET, "phonet" ) _S(AF_IEEE802154, "ieee802154" ) _S(37, "caif" ) _S(38, "alg" ) _S(39, "nfc" ) _S(40, "vsock" ) _S(41, "kcm" ) _S(42, "qipcrtr" ) _S(43, "smc" ) _S(44, "xdp" ) _S(45, "mctp" ) audit-userspace-4.0.5/auparse/fcntl-cmdtab.h000066400000000000000000000032461501761310600207720ustar00rootroot00000000000000/* fcntl-cmdtab.h -- * Copyright 2007,2012-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/fcntl.h <17 * include/uapi/linux/fcntl.h >= 1024 */ _S(0, "F_DUPFD" ) _S(1, "F_GETFD" ) _S(2, "F_SETFD" ) _S(3, "F_GETFL" ) _S(4, "F_SETFL" ) _S(5, "F_GETLK" ) _S(6, "F_SETLK" ) _S(7, "F_SETLKW" ) _S(8, "F_SETOWN" ) _S(9, "F_GETOWN" ) _S(10, "F_SETSIG" ) _S(11, "F_GETSIG" ) _S(12, "F_GETLK64" ) _S(13, "F_SETLK64" ) _S(14, "F_SETLKW64" ) _S(15, "F_SETOWN_EX" ) _S(16, "F_GETOWN_EX" ) _S(17, "F_GETOWNER_UIDS" ) _S(1024, "F_SETLEASE" ) _S(1025, "F_GETLEASE" ) _S(1026, "F_NOTIFY" ) _S(1029, "F_CANCELLK" ) _S(1030, "F_DUPFD_CLOEXEC" ) _S(1031, "F_SETPIPE_SZ" ) _S(1032, "F_GETPIPE_SZ" ) _S(1033, "F_ADD_SEALS" ) _S(1034, "F_GET_SEALS" ) _S(1035, "F_GET_RW_HINT" ) _S(1036, "F_SET_RW_HINT" ) _S(1037, "F_GET_FILE_RW_HINT" ) _S(1038, "F_SET_FILE_RW_HINT" ) audit-userspace-4.0.5/auparse/fsconfig.h000066400000000000000000000023071501761310600202270ustar00rootroot00000000000000/* fsconfig.h * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * Location: include/uapi/linux/mount.h */ _S(0, "FSCONFIG_SET_FLAG") _S(1, "FSCONFIG_SET_STRING") _S(2, "FSCONFIG_SET_BINARY") _S(3, "FSCONFIG_SET_PATH") _S(4, "FSCONFIG_SET_PATH_EMPTY") _S(5, "FSCONFIG_SET_FD") _S(6, "FSCONFIG_CMD_CREATE") _S(7, "FSCONFIG_CMD_RECONFIGURE") _S(8, "FSCONFIG_CMD_CREATE_EXCL") audit-userspace-4.0.5/auparse/icmptypetab.h000066400000000000000000000023641501761310600207550ustar00rootroot00000000000000/* icmptypetab.h -- * Copyright 2011-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/icmp.h */ _S(0, "echo-reply" ) _S(3, "destination-unreachable" ) _S(4, "source-quench" ) _S(5, "redirect" ) _S(8, "echo" ) _S(11, "time-exceeded" ) _S(12, "parameter-problem" ) _S(13, "timestamp-request" ) _S(14, "timestamp-reply" ) _S(15, "info-request" ) _S(16, "info-reply" ) _S(17, "address-mask-request" ) _S(18, "address-mask-reply" ) audit-userspace-4.0.5/auparse/inethooktab.h000066400000000000000000000020151501761310600207340ustar00rootroot00000000000000/* inethooktab.h -- * Copyright 2016 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: net/netfilter/x_tables.c textify_hooks() */ _S(0, "PREROUTING") _S(1, "INPUT") _S(2, "FORWARD") _S(3, "OUTPUT") _S(4, "POSTROUTING") _S(5, "BROUTING") audit-userspace-4.0.5/auparse/internal.h000066400000000000000000000144041501761310600202460ustar00rootroot00000000000000/* internal.h -- * Copyright 2006-07,2013-17 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef AUPARSE_INTERNAL_HEADER #define AUPARSE_INTERNAL_HEADER #include "auparse-defs.h" #include "ellist.h" #include "auditd-config.h" #include "data_buf.h" #include "normalize-llist.h" #include "dso.h" #include /* This is what state the parser is in */ typedef enum { EVENT_EMPTY, EVENT_ACCUMULATING, EVENT_EMITTED } auparser_state_t; /* * NOTES: * Auditd events are made up of one or more records. The auditd system cannot * guarantee that the set of records that make up an event will occur * atomically, that is the stream will have interleaved records of different * events. IE * ... * event0_record0 * event1_record0 * event1_record1 * event2_record0 * event1_record3 * event2_record1 * event1_record4 * event3_record0 * ... * * The auditd system does guarantee that the records that make up an event will * appear in order. Thus, when processing event streams, we need to maintain * a list of events with their own list of records hence List of List (LOL) * event processing. * * When processing an event stream we detect the end of an event via a common * function, audit_is_last_record, or the time of the event is over eoe_timeout * seconds old. eoe_timeout is the configuration item, 'end_of_event_timeout', * in the auditd.conf configuration file. It's default is EOE_TIMEOUT * * So, under LOL_EVENT processing, a event node (au_lolnode) can be either * * EBS_EMPTY: node is scheduled for emptying (freeing) * EBS_BUILDING: node is still building (awaiting more records and/or awaiting * an End of Event action) * EBS_COMPLETE: node is complete and available for use * * The old auparse() library processed events as they appeared and hence failed * to deal with interleaved records. The old library kept a 'current' event * which it would parse. This new LOL_EVENT code maintains the concept of a * 'current' event, but it now points to an event within the list of list * events structure. */ typedef enum { EBS_EMPTY, EBS_BUILDING, EBS_COMPLETE } au_lol_t; /* * Structure to hold an event and it's list of constituent records */ typedef struct _au_lolnode { event_list_t *l; /* the list of this event's records */ au_lol_t status; /* this event's build state */ } au_lolnode; /* * List of events being processed at any one time */ typedef struct { au_lolnode *array; /* array of events */ int maxi; /* largest index in array used */ size_t limit; /* number of events in array */ } au_lol; /* * The list is a dynamically growable list. We initially hold ARRAY_LIMIT * events and grow by ARRAY_LIMIT if we need to maintain more events at * any one time */ #define ARRAY_LIMIT 80 /* This is the name/value pair used by search tables */ struct nv_pair { int value; const char *name; }; typedef uint32_t value_t; typedef struct subj { value_t primary; // typically auid value_t secondary; // typically uid cllist attr; // List of attributes const char *what; // What the subject is } subject; typedef struct obj { value_t primary; value_t secondary; value_t two; // Sometimes we have a second e.g. rename/mount cllist attr; // List of attributes unsigned int what; // What the primary object is } object; typedef struct data { const char *evkind; value_t session; subject actor; const char *action; object thing; value_t results; const char *how; normalize_option_t opt; value_t key; } normalize_data; struct opaque { ausource_t source; // Source type char **source_list; // Array of buffers, or array of // file names int list_idx; // The index into the source list FILE *in; // If source is file, this is the fd unsigned int line_number; // line number of current file, zero // if invalid char *next_buf; // The current buffer being broken down unsigned int off; // The current offset into next_buf char *cur_buf; // The current buffer being parsed int line_pushed; // True if retrieve_next_line() // returns same input event_list_t *le; // Linked list of record in same event struct expr *expr; // Search expression or NULL char *find_field; // Used to store field name when // searching austop_t search_where; // Where to put the cursors on a match auparser_state_t parse_state; // parsing state DataBuf databuf; // input data // function to call to notify user of parsing changes void (*callback)(struct opaque *au, auparse_cb_event_t cb_event_type, void *user_data); void *callback_user_data; // user data supplied to callback // function to call when user_data is destroyed void (*callback_user_data_destroy)(void *user_data); au_lol *au_lo; // List of events int au_ready; // For speed, we note how many EBS_COMPLETE // events we hold at any point in time. Thus // we don't have to scan the list auparse_esc_t escape_mode; message_t message_mode; // Where to send error messages debug_message_t debug_message; // Whether or not messages are debug or not const char *tmp_translation; // Pointer to manage mem for field translation normalize_data norm_data; }; AUDIT_HIDDEN_START // auditd-config.c int aup_load_config(auparse_state_t *au, struct daemon_conf *config, log_test_t lt); void aup_free_config(struct daemon_conf *config); // normalize.c void init_normalizer(normalize_data *d); void clear_normalizer(normalize_data *d); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/interpret.c000066400000000000000000002452411501761310600204460ustar00rootroot00000000000000/* * interpret.c - Lookup values to something more readable * Copyright (c) 2007-09,2011-16,2018-21,2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include "lru.h" #include "libaudit.h" #include "internal.h" #include "interpret.h" #include "auparse-idata.h" #include "nvlist.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_IPX_HEADERS #include // FIXME: remove when ipx.h is fixed #include #endif #include #include #include #include #include /* PATH_MAX */ #ifdef USE_FANOTIFY #include #else #define FAN_ALLOW 1 #define FAN_DENY 2 #endif // This code is at the center of many performance issues. The following // ensure that it is optimized the most without making all of the audit // subsystem bigger. #pragma GCC optimize("O3") #include "auparse-defs.h" #include "gen_tables64.h" #include "common.h" #if !HAVE_DECL_ADDR_NO_RANDOMIZE # define ADDR_NO_RANDOMIZE 0x0040000 #endif /* This is from asm/ipc.h. Copying it for now as some platforms * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 #define DIPC 25 #include "captabs.h" #include "clone-flagtabs.h" #include "epoll_ctls.h" #include "famtabs.h" #include "fcntl-cmdtabs.h" #include "fsconfigs.h" #include "ipctabs.h" #include "ipccmdtabs.h" #include "mmaptabs.h" #include "mounttabs.h" #include "open-flagtabs.h" #include "persontabs.h" #include "prottabs.h" #include "ptracetabs.h" #include "recvtabs.h" #include "rlimittabs.h" #include "seektabs.h" #include "socktabs.h" #include "socktypetabs.h" #include "signaltabs.h" #include "clocktabs.h" #include "typetabs.h" #include "nfprototabs.h" #include "icmptypetabs.h" #include "seccomptabs.h" #include "accesstabs.h" #include "prctl_opttabs.h" #include "schedtabs.h" #include "shm_modetabs.h" #include "sockoptnametabs.h" #include "sockleveltabs.h" #include "ipoptnametabs.h" #include "ip6optnametabs.h" #include "tcpoptnametabs.h" #include "pktoptnametabs.h" #include "umounttabs.h" #include "ioctlreqtabs.h" #include "inethooktabs.h" #include "netactiontabs.h" #include "bpftabs.h" #include "openat2-resolvetabs.h" #include "xattr-atflagtabs.h" #include "access-flagtabs.h" typedef enum { AVC_UNSET, AVC_DENIED, AVC_GRANTED } avc_t; typedef enum { S_UNSET=-1, S_FAILED, S_SUCCESS } success_t; static char *print_escaped(const char *val); static const char *print_signals(const char *val, unsigned int base); // FIXME: move next declaration to auparse_state_t static nvlist il; // Interpretations list /* * This function will take a pointer to a 2 byte Ascii character buffer and * return the actual hex value. */ static unsigned char x2c(const unsigned char *buf) { static const char AsciiArray[17] = "0123456789ABCDEF"; char *ptr; unsigned char total=0; ptr = strchr(AsciiArray, (char)toupper(buf[0])); if (ptr) total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4); ptr = strchr(AsciiArray, (char)toupper(buf[1])); if (ptr) total += (unsigned char)((ptr-AsciiArray) & 0x0F); return total; } // Check if any characters need tty escaping. Returns how many found. static unsigned int need_tty_escape(const unsigned char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; i++; } return cnt; } // TTY escaping s string into dest. static void tty_escape(const char *s, char *dest, unsigned int len) { unsigned int i = 0, j = 0; while (i < len) { if ((unsigned char)s[i] < 32) { dest[j++] = ('\\'); dest[j++] = ('0' + ((s[i] & 0300) >> 6)); dest[j++] = ('0' + ((s[i] & 0070) >> 3)); dest[j++] = ('0' + (s[i] & 0007)); } else dest[j++] = s[i]; i++; } dest[j] = '\0'; /* terminate string */ } static const char sh_set[] = "\"'`$\\!()| "; static unsigned int need_shell_escape(const char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(sh_set, s[i])) cnt++; i++; } return cnt; } static void shell_escape(const char *s, char *dest, unsigned int len) { unsigned int i = 0, j = 0; while (i < len) { if ((unsigned char)s[i] < 32) { dest[j++] = ('\\'); dest[j++] = ('0' + ((s[i] & 0300) >> 6)); dest[j++] = ('0' + ((s[i] & 0070) >> 3)); dest[j++] = ('0' + (s[i] & 0007)); } else if (strchr(sh_set, s[i])) { dest[j++] = ('\\'); dest[j++] = s[i]; } else dest[j++] = s[i]; i++; } dest[j] = '\0'; /* terminate string */ } static const char quote_set[] = "\"'`$\\!()| ;#&*?[]<>{}"; static unsigned int need_shell_quote_escape(const unsigned char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(quote_set, s[i])) cnt++; i++; } return cnt; } static void shell_quote_escape(const char *s, char *dest, unsigned int len) { unsigned int i = 0, j = 0; while (i < len) { if ((unsigned char)s[i] < 32) { dest[j++] = ('\\'); dest[j++] = ('0' + ((s[i] & 0300) >> 6)); dest[j++] = ('0' + ((s[i] & 0070) >> 3)); dest[j++] = ('0' + (s[i] & 0007)); } else if (strchr(quote_set, s[i])) { dest[j++] = ('\\'); dest[j++] = s[i]; } else dest[j++] = s[i]; i++; } dest[j] = '\0'; /* terminate string */ } /* This should return the count of what needs escaping */ static unsigned int need_escaping(const char *s, unsigned int len, auparse_esc_t escape_mode) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: return need_tty_escape(s, len); case AUPARSE_ESC_SHELL: return need_shell_escape(s, len); case AUPARSE_ESC_SHELL_QUOTE: return need_shell_quote_escape(s, len); } return 0; } static void escape(const char *s, char *dest, unsigned int len, auparse_esc_t escape_mode) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: tty_escape(s, dest, len); break; case AUPARSE_ESC_SHELL: shell_escape(s, dest, len); break; case AUPARSE_ESC_SHELL_QUOTE: shell_quote_escape(s, dest, len); break; } } static void key_escape(const char *orig, char *dest, auparse_esc_t escape_mode) { const char *optr = orig; char *str, *dptr = dest, tmp; while (*optr) { unsigned int klen, cnt; // Find the separator or the end str = strchr(optr, AUDIT_KEY_SEPARATOR); if (str == NULL) str = strchr(optr, 0); klen = str - optr; tmp = *str; *str = 0; cnt = need_escaping(optr, klen, escape_mode); if (cnt == 0) dptr = stpcpy(dptr, optr); else { escape(optr, dptr, klen, escape_mode); dptr = strchr(dest, 0); if (dptr == NULL) return; // Something is really messed up } // Put the separator back *str = tmp; *dptr = tmp; optr = str; // If we are not at the end... if (tmp) { optr++; dptr++; } } } static int is_hex_string(const char *str) { while (*str) { if (!isxdigit(*str)) return 0; str++; } return 1; } /* returns a freshly malloc'ed and converted buffer */ char *au_unescape(char *buf) { int olen, len, i; char saved, *str, *ptr = buf; /* Find the end of the name */ if (*ptr == '(') { ptr = strchr(ptr, ')'); if (ptr == NULL) return NULL; else ptr++; } else { while (isxdigit(*ptr)) ptr++; } // Make the buffer based on size of original buffer. // This is in case we have unexpected non-hex digit // that causes truncation of the conversion and passes // back a buffer that is not sized on the expectation of // strlen(buf) / 2. olen = strlen(buf); str = malloc(olen+1); if (!str) return NULL; saved = *ptr; *ptr = 0; strcpy(str, buf); *ptr = saved; /* See if its '(null)' from the kernel */ if (*buf == '(') return str; /* We can get away with this since the buffer is 2 times * bigger than what we are putting there. */ len = strlen(str); if (len < 2) { free(str); return NULL; } ptr = str; for (i=0; i len) memset(ptr, 0, olen - len); return str; } /////////// Interpretation list functions /////////////// #define NEVER_LOADED 0xFFFF void init_interpretation_list(void) { nvlist_create(&il); il.cnt = NEVER_LOADED; } /* * Returns 0 on error and 1 on success */ int load_interpretation_list(const char *buffer) { char *saved = NULL, *ptr; char *buf, *val; nvnode n; if (buffer == NULL) return 0; if (il.cnt == NEVER_LOADED) il.cnt = 0; il.record = buf = strdup(buffer); if (buf == NULL) { goto err_out; } if (strncmp(buf, "SADDR=", 6) == 0) { // We have SOCKADDR record. It has no other values. // Handle it by itself. ptr = strchr(buf+6, '{'); if (ptr) { val = ptr; ptr = strchr(val, '}'); if (ptr) { // Just change the case n.name = strcpy(buf, "saddr"); n.val = val; if (nvlist_append(&il, &n)) goto err_out; nvlist_interp_fixup(&il); return 1; } } err_out: free(buf); il.record = NULL; il.cnt = NEVER_LOADED; return 0; } else { // We handle everything else in this branch ptr = audit_strsplit_r(buf, &saved); if (ptr == NULL) goto err_out; do { char tmp; val = strchr(ptr, '='); if (val) { *val = 0; val++; } else // Malformed - skip continue; n.name = ptr; char *c = n.name; while (*c) { *c = tolower(*c); c++; } ptr = strchr(val, ' '); if (ptr) { tmp = *ptr; *ptr = 0; } else tmp = 0; n.val = val; if (nvlist_append(&il, &n)) continue; // assuming we loaded something nvlist_interp_fixup(&il); if (ptr) *ptr = tmp; } while ((ptr = audit_strsplit_r(NULL, &saved))); } // If for some reason it was useless, delete buf if (il.cnt == 0) goto err_out; return 1; } /* * Returns malloc'ed buffer on success and NULL if no match */ const char *_auparse_lookup_interpretation(const char *name) { nvnode *n; if (il.cnt == NEVER_LOADED) return NULL; nvlist_first(&il); if (nvlist_find_name(&il, name)) { n = nvlist_get_cur(&il); // This is only called from src/ausearch-lookup.c // it only looks up auid and syscall. One needs // escape, the other does not. if (strstr(name, "id")) return print_escaped(n->interp_val); else return strdup(n->interp_val); } return NULL; } void free_interpretation_list(void) { if (il.cnt != NEVER_LOADED) { nvlist_clear(&il, 0); il.cnt = NEVER_LOADED; } } // This uses a sentinel to determine if the list has ever been loaded. // If never loaded, returns 0. Otherwise it returns 1 higher than how // many interpretations are loaded. unsigned int interpretation_list_cnt(void) { if (il.cnt == NEVER_LOADED) return 0; return il.cnt+1; } //////////// Start Field Value Interpretations ///////////// static const char *success[3]= { "unset", "no", "yes" }; static const char *aulookup_success(int s) { switch (s) { default: return success[0]; case S_FAILED: return success[1]; case S_SUCCESS: return success[2]; } } static Queue *uid_cache = NULL; static int uid_cache_created = 0; static const char *aulookup_uid(uid_t uid, char *buf, size_t size) { char *name = NULL; unsigned int key; QNode *q_node; if (uid == -1) { snprintf(buf, size, "unset"); return buf; } else if (uid == 0) { snprintf(buf, size, "root"); return buf; } // Check the cache first if (uid_cache_created == 0) { uid_cache = init_lru(19, NULL, "uid"); uid_cache_created = 1; } key = compute_subject_key(uid_cache, uid); q_node = check_lru_cache(uid_cache, key); if (q_node) { if (q_node->id == uid) name = q_node->str; else { // This getpw use is OK because its for protocol 1 // compatibility. Add it to cache. struct passwd *pw; lru_evict(uid_cache, key); q_node = check_lru_cache(uid_cache, key); pw = getpwuid(uid); if (pw) { q_node->str = strdup(pw->pw_name); q_node->id = uid; name = q_node->str; } } } if (name != NULL) snprintf(buf, size, "%s", name); else snprintf(buf, size, "unknown(%d)", uid); return buf; } void _aulookup_destroy_uid_list(void) { if (uid_cache_created == 0) return; destroy_lru(uid_cache); uid_cache_created = 0; } static Queue *gid_cache = NULL; static int gid_cache_created = 0; static const char *aulookup_gid(gid_t gid, char *buf, size_t size) { char *name = NULL; unsigned int key; QNode *q_node; if (gid == -1) { snprintf(buf, size, "unset"); return buf; } else if (gid == 0) { snprintf(buf, size, "root"); return buf; } // Check the cache first if (gid_cache_created == 0) { gid_cache = init_lru(19, NULL, "gid"); gid_cache_created = 1; } key = compute_subject_key(gid_cache, gid); q_node = check_lru_cache(gid_cache, key); if (q_node) { if (q_node->id == gid) name = q_node->str; else { // Add it to cache struct group *gr; lru_evict(gid_cache, key); q_node = check_lru_cache(gid_cache, key); gr = getgrgid(gid); if (gr) { q_node->str = strdup(gr->gr_name); q_node->id = gid; name = q_node->str; } } } if (name != NULL) snprintf(buf, size, "%s", name); else snprintf(buf, size, "unknown(%d)", gid); return buf; } void aulookup_destroy_gid_list(void) { if (gid_cache_created == 0) return; destroy_lru(gid_cache); gid_cache_created = 0; } void _auparse_flush_caches(void) { if (uid_cache_created) { destroy_lru(uid_cache); uid_cache_created = 0; } if (gid_cache_created) { destroy_lru(gid_cache); gid_cache_created = 0; } } void aulookup_metrics(unsigned int *uid, unsigned int *gid) { *uid = uid_cache->count; *gid = gid_cache->count; } static const char *print_uid(const char *val, unsigned int base) { int uid; char name[64]; errno = 0; uid = strtoul(val, NULL, base); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } return strdup(aulookup_uid(uid, name, sizeof(name))); } static const char *print_gid(const char *val, unsigned int base) { int gid; char name[64]; errno = 0; gid = strtoul(val, NULL, base); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } return strdup(aulookup_gid(gid, name, sizeof(name))); } static const char *print_arch(const char *val, unsigned int machine) { const char *ptr; char *out; if (machine > MACH_RISCV64) { unsigned int ival; errno = 0; ival = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s) ", val) < 0) out = NULL; return out; } machine = audit_elf_to_machine(ival); } if ((int)machine < 0) { if (asprintf(&out, "unknown-elf-type(%s)", val) < 0) out = NULL; return out; } ptr = audit_machine_to_name(machine); if (ptr) return strdup(ptr); else { if (asprintf(&out, "unknown-machine-type(%u)", machine) < 0) out = NULL; return out; } } static const char *print_ipccall(const char *val, unsigned int base) { int a0; char *out; const char *func = NULL; errno = 0; a0 = strtol(val, NULL, base); if (errno) { char *out2; if (asprintf(&out2, "conversion error(%s)", val) < 0) out2 = NULL; return out2; } func = ipc_i2s(a0); if (func) return strdup(func); else { if (asprintf(&out, "unknown-ipccall(%s)", val) < 0) out = NULL; return out; } } static const char *print_socketcall(const char *val, unsigned int base) { int a0; char *out; const char *func = NULL; errno = 0; a0 = strtol(val, NULL, base); if (errno) { char *out2; if (asprintf(&out2, "conversion error(%s)", val) < 0) out2 = NULL; return out2; } func = sock_i2s(a0); if (func) return strdup(func); else { if (asprintf(&out, "unknown-socketcall(%s)", val) < 0) out = NULL; return out; } } static const char *print_syscall(const idata *id) { const char *sys; char *out; int machine = id->machine, syscall = id->syscall; unsigned long long a0 = id->a0; if (machine < 0) machine = audit_detect_machine(); if (machine < 0) { out = strdup(id->val); return out; } sys = audit_syscall_to_name(syscall, machine); if (sys) { const char *func = NULL; if (strcmp(sys, "socketcall") == 0) { if ((int)a0 == a0) func = sock_i2s(a0); } else if (strcmp(sys, "ipc") == 0) if ((int)a0 == a0) func = ipc_i2s(a0); if (func) { if (asprintf(&out, "%s(%s)", sys, func) < 0) out = NULL; } else return strdup(sys); } else { if (asprintf(&out, "unknown-syscall(%d)", syscall) < 0) out = NULL; } return out; } static const char *print_exit(const char *val) { long long ival; char *out; errno = 0; ival = strtoll(val, NULL, 10); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } if (ival < 0) { if (asprintf(&out, "%s(%s)", audit_errno_to_name(-ival), strerror(-ival)) < 0) out = NULL; return out; } return strdup(val); } static char *print_escaped(const char *val) { char *out; if (val == NULL) return strdup(" "); if (*val == '"') { char *term; val++; term = strchr(val, '"'); if (term == NULL) return strdup(" "); *term = 0; out = strdup(val); *term = '"'; return out; // FIXME: working here...was trying to detect (null) and handle that // differently. The other 2 should have " around the file names. /* } else if (*val == '(') { char *term; val++; term = strchr(val, ' '); if (term == NULL) return; *term = 0; printf("%s ", val); */ } else if (val[0] == '0' && val[1] == '0') out = au_unescape((char *)&val[2]); // Abstract name af_unix else out = au_unescape((char *)val); if (out) return out; return strdup(val); // Something is wrong with string, just send as is } // This code is loosely based on glibc-2.27 realpath. static char working[PATH_MAX]; static char *path_norm(const char *name) { char *rpath, *dest; const char *start, *end, *rpath_limit; int old_errno = errno; errno = EINVAL; if (name == NULL) return NULL; if (name[0] == 0) return NULL; errno = old_errno; // If not absolute, give it back as is if (name[0] == '.') return strdup(name); rpath = working; dest = rpath; rpath_limit = rpath + PATH_MAX; for (start = name; *start; start = end) { // Remove duplicate '/' while (*start == '/') ++start; // Find end of path component for (end = start; *end && *end != '/'; ++end) ; //empty // if it ends with a slash, we're done if (end - start == 0) break; else if (end - start == 1 && start[0] == '.') ; //empty else if (end - start == 2 && start[0] == '.' && start[1] == '.') { // Back up to previous component, ignore if root while (dest > rpath && (--dest)[-1] != '/'); } else { // we need to insert a '/' if we are at the beginning // and the path is absolute or we've found the next component if ((dest == working && name[0] == '/') || (dest == working || dest[-1] != '/')) *dest++ = '/'; // If it will overflow, chop it at last component if (dest + (end - start) >= rpath_limit) { *dest = 0; break; } // Otherwise copy next component dest = mempcpy (dest, start, end - start); *dest = 0; } } return strdup(working); } static const char *print_escaped_ext(const idata *id) { if (id->cwd) { char *str1 = NULL, *str2, *str3 = NULL, *out = NULL; str2 = print_escaped(id->val); if (!str2) goto err_out; if (*str2 != '/') { // Glue the cwd and path together str1 = print_escaped(id->cwd); if (!str1) goto err_out; if (asprintf(&str3, "%s/%s", str1, str2) < 0) goto err_out; } else { // Normal looking string str3 = str2; str2 = NULL; } // Check in case /home/../etc/passwd if (strstr(str3, "..") == NULL) { free(str1); free(str2); return str3; // Nope, just return the string } out = path_norm(str3); if (!out) { // If there's an error, just return the original free(str1); free(str2); return str3; } err_out: free(str1); free(str2); free(str3); return out; } else return print_escaped(id->val); } // rawmemchr is faster. Let's use it if we have it. #ifdef HAVE_RAWMEMCHR #define STRCHR rawmemchr #else #define STRCHR strchr #endif static const char *print_proctitle(const char *val) { char *out = (char *)print_escaped(val); if (*val != '"') { size_t len = strlen(val) / 2; const char *end = out + len; char *ptr = out; // Proctitle has arguments separated by NUL bytes // We need to write over the NUL bytes with a space // so that we can see the arguments while ((ptr = STRCHR(ptr, '\0'))) { if (ptr >= end) break; *ptr = ' '; ptr++; } } return out; } static const char *print_perm(const char *val) { int ival, printed=0; char buf[32]; errno = 0; ival = strtol(val, NULL, 10); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } buf[0] = 0; /* The kernel treats nothing (0x00) as everything (0x0F) */ if (ival == 0) ival = 0x0F; if (ival & AUDIT_PERM_READ) { strcat(buf, "read"); printed = 1; } if (ival & AUDIT_PERM_WRITE) { if (printed) strcat(buf, ",write"); else strcat(buf, "write"); printed = 1; } if (ival & AUDIT_PERM_EXEC) { if (printed) strcat(buf, ",exec"); else strcat(buf, "exec"); printed = 1; } if (ival & AUDIT_PERM_ATTR) { if (printed) strcat(buf, ",attr"); else strcat(buf, "attr"); } return strdup(buf); } static const char *print_mode(const char *val, unsigned int base) { unsigned int ival; char *out, buf[48]; const char *name; errno = 0; ival = strtoul(val, NULL, base); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } // detect the file type name = audit_ftype_to_name(ival & S_IFMT); if (name != NULL) strcpy(buf, name); else { unsigned first_ifmt_bit; // The lowest-valued "1" bit in S_IFMT first_ifmt_bit = S_IFMT & ~(S_IFMT - 1); sprintf(buf, "%03o", (ival & S_IFMT) / first_ifmt_bit); } // check on special bits if (S_ISUID & ival) strcat(buf, ",suid"); if (S_ISGID & ival) strcat(buf, ",sgid"); if (S_ISVTX & ival) strcat(buf, ",sticky"); // and the read, write, execute flags in octal if (asprintf(&out, "%s,%03o", buf, (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) out = NULL; return out; } static const char *print_mode_short_int(unsigned int ival) { char *out, buf[48]; // check on special bits buf[0] = 0; if (S_ISUID & ival) strcat(buf, "suid"); if (S_ISGID & ival) { if (buf[0]) strcat(buf, ","); strcat(buf, "sgid"); } if (S_ISVTX & ival) { if (buf[0]) strcat(buf, ","); strcat(buf, "sticky"); } // and the read, write, execute flags in octal if (buf[0] == 0) { if (asprintf(&out, "0%03o", (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) out = NULL; } else if (asprintf(&out, "%s,0%03o", buf, (S_IRWXU|S_IRWXG|S_IRWXO) & ival) < 0) out = NULL; return out; } static const char *print_mode_short(const char *val, int base) { unsigned int ival; char *out; errno = 0; ival = strtoul(val, NULL, base); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } return print_mode_short_int(ival); } static const char *print_socket_domain(const char *val) { int i; char *out; const char *str; errno = 0; i = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } str = fam_i2s(i); if (str == NULL) { if (asprintf(&out, "unknown-family(0x%s)", val) < 0) out = NULL; return out; } else return strdup(str); } static const char *print_socket_type(const char *val) { unsigned int type; char *out; const char *str; errno = 0; type = 0xFF & strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } str = sock_type_i2s(type); if (str == NULL) { if (asprintf(&out, "unknown-type(%s)", val) < 0) out = NULL; return out; } else return strdup(str); } static const char *print_socket_proto(const char *val) { unsigned int proto; char *out; struct protoent *p; errno = 0; proto = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } p = getprotobynumber(proto); if (p == NULL) { if (asprintf(&out, "unknown-proto(%s)", val) < 0) out = NULL; return out; } else return strdup(p->p_name); } static const char *print_sockaddr(const char *val) { size_t slen; int rc = 0; const struct sockaddr *saddr; char name[NI_MAXHOST], serv[NI_MAXSERV]; const char *host; char *out = NULL; const char *str; slen = strlen(val)/2; host = au_unescape((char *)val); if (host == NULL) { if (asprintf(&out, "malformed-host(%s)", val) < 0) out = NULL; return out; } saddr = (struct sockaddr *)host; str = fam_i2s(saddr->sa_family); if (str == NULL) { if (asprintf(&out, "unknown-family(%d)", saddr->sa_family) < 0) out = NULL; free((char *)host); return out; } // Now print address for some families switch (saddr->sa_family) { case AF_LOCAL: if (slen < 4) { rc = asprintf(&out, "{ saddr_fam=%s %s }", str, slen == sizeof(saddr->sa_family) ? "unnamed socket" : // ignore sun_path "sockaddr len too short"); break; } else { const struct sockaddr_un *un = (const struct sockaddr_un *)saddr; if (un->sun_path[0]) rc = asprintf(&out, "{ saddr_fam=%s path=%.108s }", str, un->sun_path); else // abstract name rc = asprintf(&out, "{ saddr_fam=%s path=%.108s }", str, &un->sun_path[1]); } break; case AF_INET: if (slen < sizeof(struct sockaddr_in)) { rc = asprintf(&out, "{ saddr_fam=%s sockaddr len too short }", str); break; } slen = sizeof(struct sockaddr_in); if (getnameinfo(saddr, slen, name, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) == 0 ) { rc = asprintf(&out, "{ saddr_fam=%s laddr=%s lport=%s }", str, name, serv); } else rc = asprintf(&out, "{ saddr_fam=%s (error resolving addr) }", str); break; case AF_AX25: { const struct sockaddr_ax25 *x = (const struct sockaddr_ax25 *)saddr; rc = asprintf(&out, "{ saddr_fam=%s call=%c%c%c%c%c%c%c }", str, x->sax25_call.ax25_call[0], x->sax25_call.ax25_call[1], x->sax25_call.ax25_call[2], x->sax25_call.ax25_call[3], x->sax25_call.ax25_call[4], x->sax25_call.ax25_call[5], x->sax25_call.ax25_call[6]); } break; #ifdef HAVE_IPX_HEADERS case AF_IPX: { const struct sockaddr_ipx *ip = (const struct sockaddr_ipx *)saddr; rc = asprintf(&out, "{ saddr_fam=%s lport=%d ipx-net=%u }", str, ip->sipx_port, ip->sipx_network); } break; #endif case AF_ATMPVC: { const struct sockaddr_atmpvc* at = (const struct sockaddr_atmpvc *)saddr; rc = asprintf(&out, "{ saddr_fam=%s int=%d }", str, at->sap_addr.itf); } break; case AF_X25: { const struct sockaddr_x25* x = (const struct sockaddr_x25 *)saddr; rc = asprintf(&out, "{ saddr_fam=%s laddr=%.15s }", str, x->sx25_addr.x25_addr); } break; case AF_INET6: if (slen < sizeof(struct sockaddr_in6)) { rc = asprintf(&out, "{ saddr_fam=%s sockaddr6 len too short }", str); break; } slen = sizeof(struct sockaddr_in6); if (getnameinfo(saddr, slen, name, NI_MAXHOST, serv, NI_MAXSERV, NI_NUMERICHOST | NI_NUMERICSERV) == 0 ) { rc = asprintf(&out, "{ saddr_fam=%s laddr=%s lport=%s }", str, name, serv); } else rc = asprintf(&out, "{ saddr_fam=%s (error resolving addr) }", str); break; case AF_NETLINK: if (slen < sizeof(struct sockaddr_nl)) { rc = asprintf(&out, "{ saddr_fam=%s len too short }", str); break; } else { const struct sockaddr_nl *n = (const struct sockaddr_nl *)saddr; rc = asprintf(&out, "{ saddr_fam=%s nlnk-fam=%u nlnk-pid=%u }", str, n->nl_family, n->nl_pid); } break; default: rc = asprintf(&out, "{ saddr_fam=%s (unsupported) }", str); break; } if (rc < 0) out = NULL; free((char *)host); return out; } static const char *print_promiscuous(const char *val) { int ival; errno = 0; ival = strtol(val, NULL, 10); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } if (ival == 0) return strdup("no"); else return strdup("yes"); } static const char *print_capabilities(const char *val, int base) { int cap; char *out; const char *s; errno = 0; cap = strtoul(val, NULL, base); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = cap_i2s(cap); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-capability(%s%s)", base == 16 ? "0x" : "", val) < 0) out = NULL; return out; } static const char *print_cap_bitmap(const char *val) { #define MASK(x) (1U << (x)) unsigned long long temp; __u32 caps[2]; int i, found=0; char *p, buf[600]; // 17 per cap * 33 errno = 0; temp = strtoull(val, NULL, 16); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } caps[0] = temp & 0x00000000FFFFFFFFLL; caps[1] = (temp & 0xFFFFFFFF00000000LL) >> 32; p = buf; for (i=0; i <= CAP_LAST_CAP; i++) { if (MASK(i%32) & caps[i/32]) { const char *s; if (found) p = stpcpy(p, ","); s = cap_i2s(i); if (s != NULL) p = stpcpy(p, s); found = 1; } } if (found == 0) return strdup("none"); return strdup(buf); } static const char *print_success(const char *val) { int res; if (isdigit((unsigned char)*val)) { errno = 0; res = strtoul(val, NULL, 10); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } return strdup(aulookup_success(res)); } else return strdup(val); } static const char *print_open_flags(const char *val, int base) { size_t i; unsigned long flags; int cnt = 0; char *out, buf[sizeof(open_flag_strings)+OPEN_FLAG_NUM_ENTRIES+1]; errno = 0; flags = strtoul(val, NULL, base); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } buf[0] = 0; if ((flags & O_ACCMODE) == 0) { // Handle O_RDONLY specially strcat(buf, "O_RDONLY"); cnt++; } for (i=0; ip_name); } return out; } static const char *print_sock_opt_name(const char *val, int machine) { int opt; char *out; const char *s; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } // PPC's tables are different if ((machine == MACH_PPC64 || machine == MACH_PPC) && opt >= 16 && opt <= 21) opt+=100; s = sockoptname_i2s(opt); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-sockopt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_ip_opt_name(const char *val) { int opt; char *out; const char *s; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = ipoptname_i2s(opt); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-ipopt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_ip6_opt_name(const char *val) { int opt; char *out; const char *s; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = ip6optname_i2s(opt); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-ip6opt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_tcp_opt_name(const char *val) { int opt; char *out; const char *s; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = tcpoptname_i2s(opt); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-tcpopt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_udp_opt_name(const char *val) { int opt; char *out; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } if (opt == 1) out = strdup("UDP_CORK"); else if (opt == 100) out = strdup("UDP_ENCAP"); else if (asprintf(&out, "unknown-udpopt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_pkt_opt_name(const char *val) { int opt; char *out; const char *s; errno = 0; opt = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = pktoptname_i2s(opt); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-pktopt-name(0x%s)", val) < 0) out = NULL; return out; } static const char *print_shmflags(const char *val) { unsigned int flags, partial, i; int cnt = 0; char *out, buf[sizeof(shm_mode_strings)+sizeof(ipccmd_strings)+SHM_MODE_NUM_ENTRIES+IPCCMD_NUM_ENTRIES+1]; errno = 0; flags = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } partial = flags & 00003000; buf[0] = 0; for (i=0; imachine, syscall = id->syscall; const char* sys = audit_syscall_to_name(syscall, machine); if (sys) { if (*sys == 'r') { if (strcmp(sys, "rt_sigaction") == 0) return print_signals(val, 16); else if (strncmp(sys, "renameat", 8) == 0) return print_dirfd(val); else if (strcmp(sys, "readlinkat") == 0) return print_dirfd(val); else if (strcmp(sys, "removexattrat") == 0) return print_dirfd(val); } else if (*sys == 'c') { if (strcmp(sys, "clock_settime") == 0) return print_clock_id(val); } else if (*sys == 'p') { if (strcmp(sys, "personality") == 0) return print_personality(val); else if (strcmp(sys, "ptrace") == 0) return print_ptrace(val); else if (strcmp(sys, "prctl") == 0) return print_prctl_opt(val); } else if (*sys == 'm') { if (strcmp(sys, "mkdirat") == 0) return print_dirfd(val); else if (strcmp(sys, "mknodat") == 0) return print_dirfd(val); } else if (*sys == 'f') { if (strcmp(sys, "fchownat") == 0) return print_dirfd(val); else if (strcmp(sys, "futimesat") == 0) return print_dirfd(val); else if (strcmp(sys, "fchmodat") == 0) return print_dirfd(val); else if (strncmp(sys, "faccessat", 9) == 0) return print_dirfd(val); else if (strcmp(sys, "futimensat") == 0) return print_dirfd(val); } else if (*sys == 'u') { if (strcmp(sys, "unshare") == 0) return print_clone_flags(val); else if (strcmp(sys, "unlinkat") == 0) return print_dirfd(val); else if (strcmp(sys, "utimensat") == 0) return print_dirfd(val); } else if (strcmp(sys + 1, "etrlimit") == 0) return print_rlimit(val); else if (*sys == 's') { if (strcmp(sys, "setuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setreuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setresuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setfsuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setgid") == 0) return print_gid(val, 16); else if (strcmp(sys, "setregid") == 0) return print_gid(val, 16); else if (strcmp(sys, "setresgid") == 0) return print_gid(val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_domain(val); else if (strcmp(sys, "setfsgid") == 0) return print_gid(val, 16); else if (strcmp(sys, "socketcall") == 0) return print_socketcall(val, 16); else if (strcmp(sys, "setxattrat") == 0) return print_dirfd(val); } else if (*sys == 'l') { if (strcmp(sys, "linkat") == 0) return print_dirfd(val); else if (strcmp(sys, "listxattrat") == 0) return print_dirfd(val); } else if (strcmp(sys, "newfstatat") == 0) return print_dirfd(val); else if (strncmp(sys, "openat", 6) == 0) return print_dirfd(val); else if (strcmp(sys, "name_to_handle_at") == 0) return print_dirfd(val); else if (strcmp(sys, "ipccall") == 0) return print_ipccall(val, 16); else if (strncmp(sys, "exit", 4) == 0) return print_exit_syscall(val); else if (strcmp(sys, "bpf") == 0) return print_bpf(val); else if (strcmp(sys, "getxattrat") == 0) return print_dirfd(val); } if (asprintf(&out, "0x%s", val) < 0) out = NULL; return out; } static const char *print_a1(const char *val, const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; const char *sys = audit_syscall_to_name(syscall, machine); if (sys) { if (*sys == 'f') { if (strcmp(sys, "fchmod") == 0) return print_mode_short(val, 16); else if (strncmp(sys, "fcntl", 5) == 0) return print_fcntl_cmd(val); else if (strncmp(sys, "fsconfig", 5) == 0) return print_fsconfig(val); else if (strncmp(sys, "fsopen", 6) == 0) { if (strcmp(val, "1") == 0) return strdup("FSOPEN_CLOEXEC"); } else if (strncmp(sys, "fsmount", 7) == 0) { if (strcmp(val, "1") == 0) return strdup("FSMOUNT_CLOEXEC"); } } else if (*sys == 'c') { if (strcmp(sys, "chmod") == 0) return print_mode_short(val, 16); else if (strstr(sys, "chown")) return print_uid(val, 16); else if (strcmp(sys, "creat") == 0) return print_mode_short(val, 16); } if (strcmp(sys+1, "etsockopt") == 0) return print_sock_opt_level(val); else if (*sys == 's') { if (strcmp(sys, "setreuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setresuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setregid") == 0) return print_gid(val, 16); else if (strcmp(sys, "setresgid") == 0) return print_gid(val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_type(val); else if (strcmp(sys, "setns") == 0) return print_clone_flags(val); else if (strcmp(sys, "sched_setscheduler") == 0) return print_sched(val); } else if (*sys == 'm') { if (strcmp(sys, "mkdir") == 0) return print_mode_short(val, 16); else if (strcmp(sys, "mknod") == 0) return print_mode(val, 16); else if (strcmp(sys, "mq_open") == 0) return print_open_flags(val, 16); } else if (strcmp(sys, "open") == 0) return print_open_flags(val, 16); else if (strcmp(sys, "access") == 0) return print_access_mode(val); else if (strcmp(sys, "epoll_ctl") == 0) return print_epoll_ctl(val); else if (strcmp(sys, "kill") == 0) return print_signals(val, 16); else if (strcmp(sys, "prctl") == 0) { if (id->a0 == PR_CAPBSET_READ || id->a0 == PR_CAPBSET_DROP) return print_capabilities(val, 16); else if (id->a0 == PR_SET_PDEATHSIG) return print_signals(val, 16); } else if (strcmp(sys, "tkill") == 0) return print_signals(val, 16); else if (strcmp(sys, "umount2") == 0) return print_umount(val); else if (strcmp(sys, "ioctl") == 0) return print_ioctl_req(val); } if (asprintf(&out, "0x%s", val) < 0) out = NULL; return out; } static const char *print_a2(const char *val, const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; const char *sys = audit_syscall_to_name(syscall, machine); if (sys) { if (strncmp(sys, "fcntl", 5) == 0) { int ival; errno = 0; ival = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } switch (id->a1) { case F_SETOWN: return print_uid(val, 16); case F_SETFD: if (ival == FD_CLOEXEC) return strdup("FD_CLOEXEC"); /* Fall thru okay. */ case F_SETFL: case F_SETLEASE: case F_GETLEASE: case F_NOTIFY: break; } } else if (strcmp(sys+1, "etsockopt") == 0) { if (id->a1 == IPPROTO_IP) return print_ip_opt_name(val); else if (id->a1 == SOL_SOCKET) return print_sock_opt_name(val, machine); else if (id->a1 == IPPROTO_TCP) return print_tcp_opt_name(val); else if (id->a1 == IPPROTO_UDP) return print_udp_opt_name(val); else if (id->a1 == IPPROTO_IPV6) return print_ip6_opt_name(val); else if (id->a1 == SOL_PACKET) return print_pkt_opt_name(val); else goto normal; } else if (*sys == 'o') { if (strcmp(sys, "openat") == 0) return print_open_flags(val, 16); if ((strcmp(sys, "open") == 0) && (id->a1 & O_CREAT)) return print_mode_short(val, 16); if (strcmp(sys, "open_by_handle_at") == 0) return print_open_flags(val, 16); } else if (*sys == 'f') { if (strcmp(sys, "fchmodat") == 0) return print_mode_short(val, 16); else if (strncmp(sys, "faccessat", 9) == 0) return print_access_mode(val); else if (strncmp(sys, "fsmount", 7) == 0) return print_mount(val); } else if (*sys == 's') { if (strcmp(sys, "setresuid") == 0) return print_uid(val, 16); else if (strcmp(sys, "setresgid") == 0) return print_gid(val, 16); else if (strcmp(sys, "socket") == 0) return print_socket_proto(val); else if (strcmp(sys, "sendmsg") == 0) return print_recv(val); else if (strcmp(sys, "shmget") == 0) return print_shmflags(val); else if (strcmp(sys, "setxattrat") == 0) return print_xattr_atflags(val); } else if (*sys == 'm') { if (strcmp(sys, "mmap") == 0) return print_prot(val, 1); else if (strcmp(sys, "mkdirat") == 0) return print_mode_short(val, 16); else if (strcmp(sys, "mknodat") == 0) return print_mode_short(val, 16); else if (strcmp(sys, "mprotect") == 0) return print_prot(val, 0); else if (strcmp(sys, "move_mount") == 0) return print_dirfd(val); else if ((strcmp(sys, "mq_open") == 0) && (id->a1 & O_CREAT)) return print_mode_short(val, 16); } else if (*sys == 'r') { if (strcmp(sys, "recvmsg") == 0) return print_recv(val); else if (strcmp(sys, "readlinkat") == 0) return print_dirfd(val); else if (strncmp(sys, "renameat", 8) == 0) return print_dirfd(val); else if (strcmp(sys, "removexattrat") == 0) return print_xattr_atflags(val); } else if (*sys == 'l') { if (strcmp(sys, "linkat") == 0) return print_dirfd(val); else if (strcmp(sys, "lseek") == 0) return print_seek(val); else if (strcmp(sys, "listxattrat") == 0) return print_xattr_atflags(val); } else if (*sys == 'c') { if (strcmp(sys, "clone") == 0) return print_clone_flags(val); else if (strcmp(sys, "clone2") == 0) return print_clone_flags(val); } else if (strstr(sys, "chown")) return print_gid(val, 16); else if (strcmp(sys, "tgkill") == 0) return print_signals(val, 16); else if (strstr(sys, "getxattrat")) return print_xattr_atflags(val); } normal: if (asprintf(&out, "0x%s", val) < 0) out = NULL; return out; } static const char *print_a3(const char *val, const idata *id) { char *out; int machine = id->machine, syscall = id->syscall; const char *sys = audit_syscall_to_name(syscall, machine); if (sys) { if (*sys == 'm') { if (strcmp(sys, "mmap") == 0) return print_mmap(val); else if (strcmp(sys, "mount") == 0) return print_mount(val); } else if (*sys == 'r') { if (strcmp(sys, "recv") == 0) return print_recv(val); else if (strcmp(sys, "recvfrom") == 0) return print_recv(val); else if (strcmp(sys, "recvmmsg") == 0) return print_recv(val); } else if (*sys == 's') { if (strcmp(sys, "send") == 0) return print_recv(val); else if (strcmp(sys, "sendto") == 0) return print_recv(val); else if (strcmp(sys, "sendmmsg") == 0) return print_recv(val); } else if (*sys == 'f') { if (strcmp(sys, "faccessat") == 0) return print_access_flags(val); else if (strcmp(sys, "faccessat2") == 0) return print_access_flags(val); } } if (asprintf(&out, "0x%s", val) < 0) out = NULL; return out; } static const char *print_signals(const char *val, unsigned int base) { int i; char *out; errno = 0; i = strtoul(val, NULL, base); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } else if (i < 32) { const char *s = signal_i2s(i); if (s != NULL) return strdup(s); } if (asprintf(&out, "unknown-signal(%s%s)", base == 16 ? "0x" : "", val) < 0) out = NULL; return out; } static const char *print_nfproto(const char *val) { int proto; char *out; const char *s; errno = 0; proto = strtoul(val, NULL, 10); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = nfproto_i2s(proto); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-netfilter-protocol(%s)", val) < 0) out = NULL; return out; } static const char *print_icmptype(const char *val) { int icmptype; char *out; const char *s; errno = 0; icmptype = strtoul(val, NULL, 10); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = icmptype_i2s(icmptype); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-icmp-type(%s)", val) < 0) out = NULL; return out; } static const char *print_protocol(const char *val) { int i; char *out; errno = 0; i = strtoul(val, NULL, 10); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; } else { struct protoent *p = getprotobynumber(i); if (p) out = strdup(p->p_name); else out = strdup("undefined protocol"); } return out; } /* FIXME - this assumes inet hook. Could also be an arp hook */ static const char *print_hook(const char *val) { int hook; char *out; const char *str; errno = 0; hook = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } str = inethook_i2s(hook); if (str == NULL) { if (asprintf(&out, "unknown-hook(%s)", val) < 0) out = NULL; return out; } else return strdup(str); } static const char *print_netaction(const char *val) { int action; char *out; const char *str; errno = 0; action = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } str = netaction_i2s(action); if (str == NULL) { if (asprintf(&out, "unknown-action(%s)", val) < 0) out = NULL; return out; } else return strdup(str); } /* Ethernet packet types */ static const char *print_macproto(const char *val) { int type; char *out; errno = 0; type = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } if (type == 0x0800) return strdup("IP"); else if (type == 0x0806) return strdup("ARP"); return strdup("UNKNOWN"); } static const char *print_addr(const char *val) { char *out = strdup(val); return out; } static const char *print_list(const char *val) { int i; char *out; errno = 0; i = strtoul(val, NULL, 10); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; } else { const char *o = audit_flag_to_name(i); if (o != NULL) out = strdup(o); else if (asprintf(&out, "unknown-list(%s)", val) < 0) out = NULL; } return out; } struct string_buf { char *buf; /* NULL if was ever out of memory */ size_t allocated; size_t pos; }; /* Append c to buf. */ static void append_char(struct string_buf *buf, char c) { if (buf->buf == NULL) return; if (buf->pos == buf->allocated) { char *p; buf->allocated *= 2; p = realloc(buf->buf, buf->allocated); if (p == NULL) { free(buf->buf); buf->buf = NULL; return; } buf->buf = p; } buf->buf[buf->pos] = c; buf->pos++; } /* Represent c as a character within a quoted string, and append it to buf. */ static void tty_append_printable_char(struct string_buf *buf, unsigned char c) { if (c < 0x20 || c > 0x7E) { append_char(buf, '\\'); append_char(buf, '0' + ((c >> 6) & 07)); append_char(buf, '0' + ((c >> 3) & 07)); append_char(buf, '0' + (c & 07)); } else { if (c == '\\' || c == '"') append_char(buf, '\\'); append_char(buf, c); } } /* Search for a name of a sequence of TTY bytes. If found, return the name and advance *INPUT. Return NULL otherwise. */ static const char *tty_find_named_key(unsigned char **input, size_t input_len) { /* NUL-terminated list of (sequence, NUL, name, NUL) entries. First match wins, even if a longer match were possible later */ static const unsigned char named_keys[] = #define E(SEQ, NAME) SEQ "\0" NAME "\0" #include "tty_named_keys.h" #undef E "\0"; unsigned char *src; const unsigned char *nk; src = *input; if (*src >= ' ' && (*src < 0x7F || *src >= 0xA0)) return NULL; /* Fast path */ nk = named_keys; do { const unsigned char *p; size_t nk_len; p = strchr(nk, '\0'); nk_len = p - nk; if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) { *input += nk_len; return p + 1; } nk = strchr(p + 1, '\0') + 1; } while (*nk != '\0'); return NULL; } static const char *print_tty_data(const char *raw_data) { struct string_buf buf; int in_printable; unsigned char *data, *data_pos, *data_end; if (!is_hex_string(raw_data)) return strdup(raw_data); data = au_unescape((char *)raw_data); if (data == NULL) return NULL; data_end = data + strlen(raw_data) / 2; buf.allocated = 10; buf.buf = malloc(buf.allocated); /* NULL handled in append_char() */ buf.pos = 0; in_printable = 0; data_pos = data; while (data_pos < data_end) { /* FIXME: Unicode */ const char *desc; desc = tty_find_named_key(&data_pos, data_end - data_pos); if (desc != NULL) { if (in_printable != 0) { append_char(&buf, '"'); in_printable = 0; } if (buf.pos != 0) append_char(&buf, ','); append_char(&buf, '<'); while (*desc != '\0') { append_char(&buf, *desc); desc++; } append_char(&buf, '>'); } else { if (in_printable == 0) { if (buf.pos != 0) append_char(&buf, ','); append_char(&buf, '"'); in_printable = 1; } tty_append_printable_char(&buf, *data_pos); data_pos++; } } if (in_printable != 0) append_char(&buf, '"'); append_char(&buf, '\0'); free(data); return buf.buf; } static const char *print_session(const char *val) { if (strcmp(val, "4294967295") == 0) return strdup("unset"); else return strdup(val); } #define SECCOMP_RET_ACTION 0x7fff0000U static const char *print_seccomp_code(const char *val) { unsigned long code; char *out; const char *s; errno = 0; code = strtoul(val, NULL, 16); if (errno) { if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } s = seccomp_i2s(code & SECCOMP_RET_ACTION); if (s != NULL) return strdup(s); if (asprintf(&out, "unknown-seccomp-code(%s)", val) < 0) out = NULL; return out; } static const char *nlmcgrp[2]= { "audit-none", "audit-netlink-multicast" }; static const char *print_nlmcgrp(const char *val) { unsigned long nl; errno = 0; nl = strtoul(val, NULL, 16); if (errno) { char *out; if (asprintf(&out, "conversion error(%s)", val) < 0) out = NULL; return out; } switch (nl) { default: return strdup(nlmcgrp[0]); #ifdef AUDIT_NLGRP_MAX case AUDIT_NLGRP_READLOG: return strdup(nlmcgrp[1]); #endif } } int lookup_type(const char *name) { int i; if (type_s2i(name, &i) != 0) return i; return AUPARSE_TYPE_UNCLASSIFIED; } /* * This is the main entry point for the auparse library. Call chain is: * auparse_interpret_field -> nvlist_interp_cur_val -> do_interpret */ const char *do_interpret(rnode *r, auparse_esc_t escape_mode) { nvlist *nv = &r->nv; int type; idata id; nvnode *n; const char *out; id.machine = r->machine; id.syscall = r->syscall; id.a0 = r->a0; id.a1 = r->a1; id.cwd = r->cwd; id.name = nvlist_get_cur_name(nv); id.val = nvlist_get_cur_val(nv); type = auparse_interp_adjust_type(r->type, id.name, id.val); out = auparse_do_interpretation(type, &id, escape_mode); n = nvlist_get_cur(nv); n->interp_val = (char *)out; return out; } /* * rtype: the record type * name: the current field name * value: the current field value * Returns: field's internal type is returned */ int auparse_interp_adjust_type(int rtype, const char *name, const char *val) { int type; /* This set of statements overrides or corrects the detection. * In almost all cases its a double use of a field. */ if (rtype == AUDIT_EXECVE && *name == 'a' && strcmp(name, "argc") && !strstr(name, "_len")) type = AUPARSE_TYPE_ESCAPED; else if (rtype == AUDIT_AVC && strcmp(name, "saddr") == 0) type = AUPARSE_TYPE_UNCLASSIFIED; else if (rtype == AUDIT_USER_TTY && strcmp(name, "msg") == 0) type = AUPARSE_TYPE_ESCAPED; else if (rtype == AUDIT_NETFILTER_PKT && strcmp(name, "saddr") == 0) type = AUPARSE_TYPE_ADDR; else if (strcmp(name, "acct") == 0) { if (val[0] == '"') type = AUPARSE_TYPE_ESCAPED; else if (is_hex_string(val)) type = AUPARSE_TYPE_ESCAPED; else type = AUPARSE_TYPE_UNCLASSIFIED; } else if (rtype == AUDIT_MQ_OPEN && strcmp(name, "mode") == 0) type = AUPARSE_TYPE_MODE_SHORT; else if (rtype == AUDIT_CRYPTO_KEY_USER && strcmp(name, "fp") == 0) type = AUPARSE_TYPE_UNCLASSIFIED; else if ((strcmp(name, "id") == 0) && (rtype == AUDIT_ADD_GROUP || rtype == AUDIT_GRP_MGMT || rtype == AUDIT_DEL_GROUP)) type = AUPARSE_TYPE_GID; else if (rtype == AUDIT_TRUSTED_APP) { /* * Could be anything. See if we know the type. If not, * take a guess based on contents of value. */ type = lookup_type(name); if (type == AUPARSE_TYPE_UNCLASSIFIED) { if (val[0] == '"') type = AUPARSE_TYPE_ESCAPED; else if (strcmp(name, "pid") == 0) type = AUPARSE_TYPE_UNCLASSIFIED; /* Check if we have string with only HEX symbols */ else if (is_hex_string(val)) type = AUPARSE_TYPE_ESCAPED; /* Otherwise it really is AUPARSE_TYPE_UNCLASSIFIED */ } } else if (rtype == AUDIT_KERN_MODULE && strcmp(name, "name") == 0) type = AUPARSE_TYPE_ESCAPED; else type = lookup_type(name); return type; } /* * This can be called by either interpret() or from ausearch-report or * auditctl-listing.c. Returns a malloc'ed buffer that the caller must free. */ char *auparse_do_interpretation(int type, const idata *id, auparse_esc_t escape_mode) { const char *out; // Check the interpretations list first if (interpretation_list_cnt()) { nvlist_first(&il); if (nvlist_find_name(&il, id->name)) { nvnode* node = &il.array[il.cur]; const char *val = node->interp_val; if (val) { // If we don't know what it is when auditd // recorded it, try it again incase the // libraries have been updated to support it. if (strncmp(val, "unknown-", 8 ) == 0) goto unknown; if (type == AUPARSE_TYPE_UID || type == AUPARSE_TYPE_GID) return print_escaped(val); else return strdup(val); } } } unknown: switch(type) { case AUPARSE_TYPE_UID: out = print_uid(id->val, 10); break; case AUPARSE_TYPE_GID: out = print_gid(id->val, 10); break; case AUPARSE_TYPE_SYSCALL: out = print_syscall(id); break; case AUPARSE_TYPE_ARCH: out = print_arch(id->val, id->machine); break; case AUPARSE_TYPE_EXIT: out = print_exit(id->val); break; case AUPARSE_TYPE_ESCAPED: case AUPARSE_TYPE_ESCAPED_FILE: out = print_escaped_ext(id); break; case AUPARSE_TYPE_ESCAPED_KEY: out = print_escaped(id->val); break; case AUPARSE_TYPE_PERM: out = print_perm(id->val); break; case AUPARSE_TYPE_MODE: out = print_mode(id->val,8); break; case AUPARSE_TYPE_MODE_SHORT: out = print_mode_short(id->val,8); break; case AUPARSE_TYPE_SOCKADDR: out = print_sockaddr(id->val); break; case AUPARSE_TYPE_PROMISC: out = print_promiscuous(id->val); break; case AUPARSE_TYPE_CAPABILITY: out = print_capabilities(id->val, 10); break; case AUPARSE_TYPE_SUCCESS: out = print_success(id->val); break; case AUPARSE_TYPE_A0: out = print_a0(id->val, id); break; case AUPARSE_TYPE_A1: out = print_a1(id->val, id); break; case AUPARSE_TYPE_A2: out = print_a2(id->val, id); break; case AUPARSE_TYPE_A3: out = print_a3(id->val, id); break; case AUPARSE_TYPE_SIGNAL: out = print_signals(id->val, 10); break; case AUPARSE_TYPE_LIST: out = print_list(id->val); break; case AUPARSE_TYPE_TTY_DATA: out = print_tty_data(id->val); break; case AUPARSE_TYPE_SESSION: out = print_session(id->val); break; case AUPARSE_TYPE_CAP_BITMAP: out = print_cap_bitmap(id->val); break; case AUPARSE_TYPE_NFPROTO: out = print_nfproto(id->val); break; case AUPARSE_TYPE_ICMPTYPE: out = print_icmptype(id->val); break; case AUPARSE_TYPE_PROTOCOL: out = print_protocol(id->val); break; case AUPARSE_TYPE_ADDR: out = print_addr(id->val); break; case AUPARSE_TYPE_PERSONALITY: out = print_personality(id->val); break; case AUPARSE_TYPE_SECCOMP: out = print_seccomp_code(id->val); break; case AUPARSE_TYPE_OFLAG: // AUDIT_OPENAT2,MQ_OPEN out = print_open_flags(id->val, 0); break; case AUPARSE_TYPE_MMAP: out = print_mmap(id->val); break; case AUPARSE_TYPE_PROCTITLE: out = print_proctitle(id->val); break; case AUPARSE_TYPE_HOOK: out = print_hook(id->val); break; case AUPARSE_TYPE_NETACTION: out = print_netaction(id->val); break; case AUPARSE_TYPE_MACPROTO: out = print_macproto(id->val); break; case AUPARSE_TYPE_IOCTL_REQ: out = print_ioctl_req(id->val); break; case AUPARSE_TYPE_FANOTIFY: out = print_fanotify(id->val); break; case AUPARSE_TYPE_NLMCGRP: out = print_nlmcgrp(id->val); break; case AUPARSE_TYPE_RESOLVE: out = print_openat2_resolve(id->val); break; case AUPARSE_TYPE_TRUST: out = print_trust(id->val); break; case AUPARSE_TYPE_FAN_TYPE: out = print_fan_type(id->val); break; case AUPARSE_TYPE_FAN_INFO: out = print_fan_info(id->val); break; case AUPARSE_TYPE_ERRNO: out = print_errno(id->val); break; case AUPARSE_TYPE_MAC_LABEL: case AUPARSE_TYPE_UNCLASSIFIED: default: out = strdup(id->val); break; } if (escape_mode != AUPARSE_ESC_RAW && out) { char *str = NULL; unsigned int len = strlen(out); if (type == AUPARSE_TYPE_ESCAPED_KEY) { // The audit key separator causes a false // positive in deciding to escape. str = strchr(out, AUDIT_KEY_SEPARATOR); } if (str == NULL) { // This is the normal path unsigned int cnt = need_escaping(out, len, escape_mode); if (cnt) { char *dest = malloc(len + 1 + (3*cnt)); if (dest) escape(out, dest, len, escape_mode); free((void *)out); out = dest; } } else { // We have multiple keys. Need to look at each one. unsigned int cnt = 0; char *ptr = (char *)out; while (*ptr) { unsigned int klen = str - ptr; char tmp = *str; *str = 0; cnt += need_escaping(ptr, klen, escape_mode); *str = tmp; ptr = str; // If we are not at the end... if (tmp) { ptr++; str = strchr(ptr, AUDIT_KEY_SEPARATOR); // If we don't have anymore, just // point to the end if (str == NULL) str = strchr(ptr, 0); } } if (cnt) { // I expect this code to never get used. // Its here just in the off chance someone // actually put a control character in a key. char *dest = malloc(len + 1 + (3*cnt)); if (dest) { // Because need_escaping was called // terminated, we need to do the same // incase there's a Ctl-A in the key. // This is likely fuzzer induced. char tmp; str = strchr(out, AUDIT_KEY_SEPARATOR); if (str) { tmp = *str; *str = 0; key_escape(out, dest, escape_mode); *str = tmp; } else key_escape(out, dest, escape_mode); } free((void *)out); out = dest; } } } return (char *)out; } audit-userspace-4.0.5/auparse/interpret.h000066400000000000000000000030311501761310600204400ustar00rootroot00000000000000/* interpret.h -- * Copyright 2007,08,2016-23 Red Hat Inc. * All Rights Reserved. * * 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef INTERPRET_HEADER #define INTERPRET_HEADER #include "config.h" #include "dso.h" #include "rnode.h" #include /* Make these hidden to prevent conflicts */ AUDIT_HIDDEN_START void init_interpretation_list(void); int load_interpretation_list(const char *buf); void free_interpretation_list(void); unsigned int interpretation_list_cnt(void); int lookup_type(const char *name); const char *do_interpret(rnode *r, auparse_esc_t escape_mode); void _aulookup_destroy_uid_list(void); void aulookup_destroy_gid_list(void); void aulookup_metrics(unsigned int *uid, unsigned int *gid); char *au_unescape(char *buf); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/ioctlreqtab.h000066400000000000000000000036701501761310600207460ustar00rootroot00000000000000/* ioctlreqtab.h -- * Copyright 2014 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * * This list is not comprehensive. Its just some cherry picked ioctls. * include/uapi/linux/kd.h * include/uapi/linux/cdrom.h * include/uapi/asm-generic/ioctls.h * include/uapi/drm/drm.h */ _S(0x4B3A, "KDSETMODE" ) _S(0x4B3B, "KDGETMODE" ) _S(0x5309, "CDROMEJECT" ) _S(0x530F, "CDROMEJECT_SW" ) _S(0x5311, "CDROM_GET_UPC" ) _S(0x5316, "CDROMSEEK" ) _S(0x5401, "TCGETS" ) _S(0x5402, "TCSETS" ) _S(0x5403, "TCSETSW" ) _S(0x5404, "TCSETSF" ) _S(0x5409, "TCSBRK" ) _S(0x540B, "TCFLSH" ) _S(0x540E, "TIOCSCTTY" ) _S(0x540F, "TIOCGPGRP" ) _S(0x5410, "TIOCSPGRP" ) _S(0x5413, "TIOCGWINSZ" ) _S(0x5414, "TIOCSWINSZ" ) _S(0x541B, "TIOCINQ" ) _S(0x5421, "FIONBIO" ) _S(0x5422, "TIOCNOTTY" ) _S(0x8901, "FIOSETOWN" ) _S(0x8903, "FIOGETOWN" ) _S(0x8910, "SIOCGIFNAME" ) _S(0x8927, "SIOCGIFHWADDR" ) _S(0x8933, "SIOCGIFINDEX" ) _S(0x89a2, "SIOCBRADDIF" ) _S(0x40045431, "TIOCSPTLCK" ) // Need a better fix for these _S(0x80045430, "TIOCGPTN" ) _S(0x80045431, "TIOCSPTLCK" ) _S(0xC01C64A3, "DRM_IOCTL_MODE_CURSOR" ) _S(0xC01864B0, "DRM_IOCTL_MODE_PAGE_FLIP" ) _S(0xC01864B1, "DRM_IOCTL_MODE_DIRTYFB" ) audit-userspace-4.0.5/auparse/ip6optnametab.h000066400000000000000000000056241501761310600212070ustar00rootroot00000000000000/* ip6optnametab.h -- * Copyright 2013-16,2018,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/in6.h (all ^IPV6_ && ^MCAST_) * include/uapi/linux/netfilter_ipv6/ip6_tables.h (all ^IP6T_) * include/uapi/linux/mroute6.h (not used?) */ _S(1, "IPV6_ADDRFORM") _S(2, "IPV6_2292PKTINFO") _S(3, "IPV6_2292HOPOPTS") _S(4, "IPV6_2292DSTOPTS") _S(5, "IPV6_2292RTHDR") _S(6, "IPV6_2292PKTOPTIONS") _S(7, "IPV6_CHECKSUM") _S(8, "IPV6_2292HOPLIMIT") _S(9, "IPV6_NEXTHOP") _S(10, "IPV6_AUTHHDR") _S(11, "IPV6_FLOWINFO") _S(16, "IPV6_UNICAST_HOPS") _S(17, "IPV6_MULTICAST_IF") _S(18, "IPV6_MULTICAST_HOPS") _S(19, "IPV6_MULTICAST_LOOP") _S(20, "IPV6_ADD_MEMBERSHIP") _S(21, "IPV6_DROP_MEMBERSHIP") _S(22, "IPV6_ROUTER_ALERT") _S(23, "IPV6_MTU_DISCOVER") _S(24, "IPV6_MTU") _S(25, "IPV6_RECVERR") _S(26, "IPV6_V6ONLY") _S(27, "IPV6_JOIN_ANYCAST") _S(28, "IPV6_LEAVE_ANYCAST") _S(29, "IPV6_MULTICAST_ALL") _S(30, "IPV6_ROUTER_ALERT_ISOLATE") _S(31, "IPV6_RECVERR_RFC4884") _S(32, "IPV6_FLOWLABEL_MGR") _S(33, "IPV6_FLOWINFO_SEND") _S(34, "IPV6_IPSEC_POLICY") _S(35, "IPV6_XFRM_POLICY") _S(36, "IPV6_HDRINCL") _S(42, "MCAST_JOIN_GROUP") _S(43, "MCAST_BLOCK_SOURCE") _S(44, "MCAST_UNBLOCK_SOURCE") _S(45, "MCAST_LEAVE_GROUP") _S(46, "MCAST_JOIN_SOURCE_GROUP") _S(47, "MCAST_LEAVE_SOURCE_GROUP") _S(48, "MCAST_MSFILTER") _S(49, "IPV6_RECVPKTINFO") _S(50, "IPV6_PKTINFO") _S(51, "IPV6_RECVHOPLIMIT") _S(52, "IPV6_HOPLIMIT") _S(53, "IPV6_RECVHOPOPTS") _S(54, "IPV6_HOPOPTS") _S(55, "IPV6_RTHDRDSTOPTS") _S(56, "IPV6_RECVRTHDR") _S(57, "IPV6_RTHDR") _S(58, "IPV6_RECVDSTOPTS") _S(59, "IPV6_DSTOPTS") _S(60, "IPV6_RECVPATHMTU") _S(61, "IPV6_PATHMTU") _S(62, "IPV6_DONTFRAG") _S(63, "IPV6_USE_MIN_MTU") _S(64, "IP6T_SO_SET_REPLACE") _S(65, "IP6T_SO_SET_ADD_COUNTERS") _S(66, "IPV6_RECVTCLASS") _S(67, "IPV6_TCLASS") _S(68, "IP6T_SO_GET_REVISION_MATCH") _S(69, "IP6T_SO_GET_REVISION_TARGET") _S(70, "IPV6_AUTOFLOWLABEL") _S(72, "IPV6_ADDR_PREFERENCES") _S(73, "IPV6_MINHOPCOUNT") _S(74, "IPV6_ORIGDSTADDR") _S(75, "IPV6_TRANSPARENT") _S(76, "IPV6_UNICAST_IF") _S(77, "IPV6_RECVFRAGSIZE") _S(78, "IPV6_FREEBIND") _S(80, "IP6T_SO_ORIGINAL_DST") audit-userspace-4.0.5/auparse/ipccmdtab.h000066400000000000000000000017411501761310600203600ustar00rootroot00000000000000/* ipccmdtab.h -- * Copyright 2013 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/ipc.h */ _S(00001000, "IPC_CREAT" ) _S(00002000, "IPC_EXCL" ) _S(00004000, "IPC_NOWAIT" ) audit-userspace-4.0.5/auparse/ipctab.h000066400000000000000000000022551501761310600176750ustar00rootroot00000000000000/* ipctab.h -- * Copyright 2007,2012-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/ipc.h */ _S(SEMOP, "semop" ) _S(SEMGET, "semget" ) _S(SEMCTL, "semctl" ) _S(4, "semtimedop" ) _S(MSGSND, "msgsnd" ) _S(MSGRCV, "msgrcv" ) _S(MSGGET, "msgget" ) _S(MSGCTL, "msgctl" ) _S(SHMAT, "shmat" ) _S(SHMDT, "shmdt" ) _S(SHMGET, "shmget" ) _S(SHMCTL, "shmctl" ) _S(DIPC, "dipc" ) audit-userspace-4.0.5/auparse/ipoptnametab.h000066400000000000000000000043001501761310600211070ustar00rootroot00000000000000/* ipoptnametab.h -- * Copyright 2013,2015,2018,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/in.h * include/uapi/linux/netfilter_ipv4/ip_tables.h */ _S(1, "IP_TOS") _S(2, "IP_TTL") _S(3, "IP_HDRINCL") _S(4, "IP_OPTIONS") _S(5, "IP_ROUTER_ALERT") _S(6, "IP_RECVOPTS") _S(7, "IP_RETOPTS") _S(8, "IP_PKTINFO") _S(9, "IP_PKTOPTIONS") _S(10, "IP_MTU_DISCOVER") _S(11, "IP_RECVERR") _S(12, "IP_RECVTTL") _S(13, "IP_RECVTOS") _S(14, "IP_MTU") _S(15, "IP_FREEBIND") _S(16, "IP_IPSEC_POLICY") _S(17, "IP_XFRM_POLICY") _S(18, "IP_PASSSEC") _S(19, "IP_TRANSPARENT") _S(20, "IP_ORIGDSTADDR") _S(21, "IP_MINTTL") _S(22, "IP_NODEFRAG") _S(23, "IP_CHECKSUM") _S(24, "IP_BIND_ADDRESS_NO_PORT") _S(25, "IP_RECVFRAGSIZE") _S(32, "IP_MULTICAST_IF") _S(33, "IP_MULTICAST_TTL") _S(34, "IP_MULTICAST_LOOP") _S(35, "IP_ADD_MEMBERSHIP") _S(36, "IP_DROP_MEMBERSHIP") _S(37, "IP_UNBLOCK_SOURCE") _S(38, "IP_BLOCK_SOURCE") _S(39, "IP_ADD_SOURCE_MEMBERSHIP") _S(40, "IP_DROP_SOURCE_MEMBERSHIP") _S(41, "IP_MSFILTER") _S(42, "MCAST_JOIN_GROUP") _S(43, "MCAST_BLOCK_SOURCE") _S(44, "MCAST_UNBLOCK_SOURCE") _S(45, "MCAST_LEAVE_GROUP") _S(46, "MCAST_JOIN_SOURCE_GROUP") _S(47, "MCAST_LEAVE_SOURCE_GROUP") _S(48, "MCAST_MSFILTER") _S(49, "IP_MULTICAST_ALL") _S(50, "IP_UNICAST_IF") _S(51, "IP_LOCAL_PORT_RANGE") _S(52, "IP_PROTOCOL") _S(64, "IPT_SO_SET_REPLACE") _S(65, "IPT_SO_SET_ADD_COUNTERS") _S(66, "IPT_SO_GET_REVISION_TARGET") audit-userspace-4.0.5/auparse/lru.c000066400000000000000000000202771501761310600172340ustar00rootroot00000000000000/* * lru.c - LRU cache implementation * Copyright (c) 2016-17,20 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include "lru.h" //#define DEBUG #ifdef DEBUG #include #endif // Local declarations static void dequeue(Queue *queue); // The Queue Node will store the 'str' being cached static QNode *new_QNode(void) { QNode *temp = malloc(sizeof(QNode)); if (temp == NULL) return temp; temp->str = NULL; temp->id = (unsigned int)-1; temp->uses = 1; // Setting to 1 because its being used // Initialize prev and next as NULL temp->prev = temp->next = NULL; return temp; } static Hash *create_hash(unsigned int hsize) { unsigned int i; Hash *hash = malloc(sizeof(Hash)); if (hash == NULL) return hash; hash->array = malloc(hsize * sizeof(QNode*)); if (hash->array == NULL) { free(hash); return NULL; } // Initialize all hash entries as empty for (i = 0; i < hsize; i++) hash->array[i] = NULL; return hash; } static void destroy_hash(Hash *hash) { free(hash->array); free(hash); } #ifdef DEBUG static void dump_queue_stats(const Queue *q) { syslog(LOG_DEBUG, "%s queue size: %u", q->name, q->total); syslog(LOG_DEBUG, "%s slots in use: %u", q->name, q->count); syslog(LOG_DEBUG, "%s hits: %lu", q->name, q->hits); syslog(LOG_DEBUG, "%s misses: %lu", q->name, q->misses); syslog(LOG_DEBUG, "%s evictions: %lu", q->name, q->evictions); } #endif static Queue *create_queue(unsigned int qsize, const char *name) { Queue *queue = malloc(sizeof(Queue)); if (queue == NULL) return queue; // The queue is empty queue->count = 0; queue->hits = 0; queue->misses = 0; queue->evictions = 0; queue->front = queue->end = NULL; // Number of slots that can be stored in memory queue->total = qsize; queue->name = name; return queue; } static void destroy_queue(Queue *queue) { #ifdef DEBUG dump_queue_stats(queue); #endif // Some static analysis scanners try to flag this as a use after // free accessing queue->end. This is a false positive. It is freed. // However, static analysis apps are incapable of seeing that in // remove_node, end is updated to a prior node as part of detaching // the current end node. while (queue->count) dequeue(queue); free(queue); } static unsigned int are_all_slots_full(const Queue *queue) { return queue->count == queue->total; } static unsigned int queue_is_empty(const Queue *queue) { return queue->end == NULL; } #ifdef DEBUG static void sanity_check_queue(Queue *q, const char *id) { unsigned int i; QNode *n; if (q == NULL) { syslog(LOG_DEBUG, "%s - q is NULL", id); abort(); } n = q->front; if (n == NULL) return; // Walk bottom to top i = 0; while (n->next) { if (n->next->prev != n) { syslog(LOG_DEBUG, "%s - corruption found %u", id, i); abort(); } if (i == q->count) { syslog(LOG_DEBUG, "%s - forward loop found %u", id, i); abort(); } i++; n = n->next; } // Walk top to bottom n = q->end; while (n->prev) { if (n->prev->next != n) { syslog(LOG_DEBUG, "%s - Corruption found %u", id, i); abort(); } if (i == 0) { syslog(LOG_DEBUG, "%s - backward loop found %u", id, i); abort(); } i--; n = n->prev; } } #else #define sanity_check_queue(a, b) do {} while(0) #endif static void insert_before(Queue *queue, QNode *node, QNode *new_node) { sanity_check_queue(queue, "1 insert_before"); if (queue == NULL || node == NULL || new_node == NULL) return; new_node->prev = node->prev; new_node->next = node; if (node->prev == NULL) queue->front = new_node; else node->prev->next = new_node; node->prev = new_node; sanity_check_queue(queue, "2 insert_before"); } static void insert_beginning(Queue *queue, QNode *new_node) { sanity_check_queue(queue, "1 insert_beginning"); if (queue == NULL || new_node == NULL) return; if (queue->front == NULL) { queue->front = new_node; queue->end = new_node; new_node->prev = NULL; new_node->next = NULL; } else insert_before(queue, queue->front, new_node); sanity_check_queue(queue, "2 insert_beginning"); } static void remove_node(Queue *queue, const QNode *node) { // If we are at the beginning sanity_check_queue(queue, "1 remove_node"); if (node->prev == NULL) { queue->front = node->next; if (queue->front) queue->front->prev = NULL; goto out; } else { if (node->prev->next != node) { #ifdef DEBUG syslog(LOG_ERR, "Linked list corruption detected %s", queue->name); #endif abort(); } node->prev->next = node->next; } // If we are at the end if (node->next == NULL) { queue->end = node->prev; if (queue->end) queue->end->next = NULL; } else { if (node->next->prev != node) { #ifdef DEBUG syslog(LOG_ERR, "Linked List corruption detected %s", queue->name); #endif abort(); } node->next->prev = node->prev; } out: sanity_check_queue(queue, "2 remove_node"); } // Remove from the end of the queue static void dequeue(Queue *queue) { if (queue_is_empty(queue)) return; QNode *temp = queue->end; remove_node(queue, queue->end); // if (queue->cleanup) // queue->cleanup(temp->str); free(temp->str); free(temp); // decrement the total of full slots by 1 queue->count--; } // Remove front of the queue because its a mismatch void lru_evict(Queue *queue, unsigned int key) { if (queue_is_empty(queue)) return; Hash *hash = queue->hash; QNode *temp = queue->front; hash->array[key] = NULL; remove_node(queue, queue->front); // if (queue->cleanup) // queue->cleanup(temp->str); free(temp->str); free(temp); // decrement the total of full slots by 1 queue->count--; queue->evictions++; } // Make a new entry with str to be assigned later // and setup the hash key static void enqueue(Queue *queue, unsigned int key) { QNode *temp; Hash *hash = queue->hash; // If all slots are full, remove the page at the end if (are_all_slots_full(queue)) { // remove page from hash hash->array[key] = NULL; dequeue(queue); } // Create a new node with given page total, // And add the new node to the front of queue temp = new_QNode(); insert_beginning(queue, temp); hash->array[key] = temp; // increment number of full slots queue->count++; } // This function is called needing a str from cache. // There are two scenarios: // 1. Item is not in cache, so add it to the front of the queue // 2. Item is in cache, we move the str to front of queue QNode *check_lru_cache(Queue *queue, unsigned int key) { QNode *reqPage; Hash *hash = queue->hash; // Check for out of bounds key if (key >= queue->total) { return NULL; } reqPage = hash->array[key]; // str is not in cache, make new spot for it if (reqPage == NULL) { enqueue(queue, key); queue->misses++; // str is there but not at front. Move it } else if (reqPage != queue->front) { remove_node(queue, reqPage); reqPage->next = NULL; reqPage->prev = NULL; insert_beginning(queue, reqPage); // Increment cached object metrics queue->front->uses++; queue->hits++; } else queue->hits++; return queue->front; } Queue *init_lru(unsigned int qsize, void (*cleanup)(void *), const char *name) { Queue *q = create_queue(qsize, name); if (q == NULL) return q; q->cleanup = cleanup; q->hash = create_hash(qsize); return q; } void destroy_lru(Queue *queue) { if (queue == NULL) return; destroy_hash(queue->hash); destroy_queue(queue); } unsigned int compute_subject_key(const Queue *queue, unsigned int uid) { if (queue) return uid % queue->total; else return 0; } audit-userspace-4.0.5/auparse/lru.h000066400000000000000000000042551501761310600172370ustar00rootroot00000000000000/* * lru.h - Header file for lru.c * Copyright (c) 2016.2017 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef LRU_HEADER #define LRU_HEADER #include "dso.h" /* Make these hidden to prevent conflicts */ AUDIT_HIDDEN_START // Queue is implemented using double linked list typedef struct QNode { struct QNode *prev; struct QNode *next; unsigned long uses; unsigned int id; void *str; // the data in the cache } QNode; // Collection of pointers to Queue Nodes typedef struct Hash { unsigned int size; // how many entries QNode **array; // an array of queue nodes } Hash; // FIFO of Queue Nodes typedef struct Queue { unsigned int count; // Number of filled slots unsigned int total; // total number of slots unsigned long hits; // Number of times object was in cache unsigned long misses;// number of times object was not in cache unsigned long evictions;// number of times cached object was not usable QNode *front; QNode *end; Hash *hash; const char *name; // Used for reporting void (*cleanup)(void *); // Function to call when releasing memory } Queue; Queue *init_lru(unsigned int qsize, void (*cleanup)(void *), const char *name); void destroy_lru(Queue *queue); void lru_evict(Queue *queue, unsigned int key); QNode *check_lru_cache(Queue *q, unsigned int key); unsigned int compute_subject_key(const Queue *queue, unsigned int uid); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/message.c000066400000000000000000000033211501761310600200450ustar00rootroot00000000000000/* message.c -- * Copyright 2004, 2005 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include "libaudit.h" #include "private.h" #include "internal.h" /* The message mode refers to where informational messages go 0 - stderr, 1 - syslog, 2 - quiet. The default is quiet. */ void set_aumessage_mode(auparse_state_t *au, message_t mode, debug_message_t debug) { au->message_mode = mode; au->debug_message = debug; } void audit_msg(const auparse_state_t *au, int priority, const char *fmt, ...) { va_list ap; if (au->message_mode == MSG_QUIET) return; if (priority == LOG_DEBUG && au->debug_message == DBG_NO) return; va_start(ap, fmt); if (au->message_mode == MSG_SYSLOG) vsyslog(priority, fmt, ap); else { vfprintf(stderr, fmt, ap); fputc('\n', stderr); } va_end( ap ); } audit-userspace-4.0.5/auparse/mmaptab.h000066400000000000000000000027731501761310600200610ustar00rootroot00000000000000/* mmaptab.h -- * Copyright 2012-13,2018,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/mman-common.h * 0x0100 - 0x4000 flags are defined in include/uapi/asm-generic/mman.h */ _S(0x0000001, "MAP_SHARED" ) _S(0x0000002, "MAP_PRIVATE" ) _S(0x0000010, "MAP_FIXED" ) _S(0x0000020, "MAP_ANONYMOUS" ) _S(0x0000040, "MAP_32BIT" ) _S(0x0000100, "MAP_GROWSDOWN" ) _S(0x0000800, "MAP_DENYWRITE" ) _S(0x0001000, "MAP_EXECUTABLE" ) _S(0x0002000, "MAP_LOCKED" ) _S(0x0004000, "MAP_NORESERVE" ) _S(0x0008000, "MAP_POPULATE" ) _S(0x0010000, "MAP_NONBLOCK" ) _S(0x0020000, "MAP_STACK" ) _S(0x0040000, "MAP_HUGETLB" ) _S(0x0080000, "MAP_SYNC" ) _S(0x0100000, "MAP_FIXED_NOREPLACE") _S(0x4000000, "MAP_UNINITIALIZED") audit-userspace-4.0.5/auparse/mounttab.h000066400000000000000000000034631501761310600202660ustar00rootroot00000000000000/* mounttab.h -- * Copyright 2012-13,2018,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/mount.h * NOTE: When updating this table, update interpret.c:print_mount() */ _S(MS_RDONLY, "MS_RDONLY") _S(MS_NOSUID, "MS_NOSUID") _S(MS_NODEV, "MS_NODEV" ) _S(MS_NOEXEC, "MS_NOEXEC") _S(MS_SYNCHRONOUS, "MS_SYNCHRONOUS") _S(MS_REMOUNT, "MS_REMOUNT") _S(MS_MANDLOCK, "MS_MANDLOCK") _S(MS_DIRSYNC, "MS_DIRSYNC") _S(MS_NOATIME, "MS_NOATIME") _S(MS_NODIRATIME, "MS_NODIRATIME") _S(MS_BIND, "MS_BIND") _S(MS_MOVE, "MS_MOVE") _S(MS_REC, "MS_REC") _S(MS_SILENT, "MS_SILENT") _S(MS_POSIXACL, "MS_POSIXACL") _S(MS_UNBINDABLE, "MS_UNBINDABLE") _S(MS_PRIVATE, "MS_PRIVATE") _S(MS_SLAVE, "MS_SLAVE") _S(MS_SHARED, "MS_SHARED") _S(MS_RELATIME, "MS_RELATIME") _S(MS_KERNMOUNT, "MS_KERNMOUNT") _S(MS_I_VERSION, "MS_I_VERSION") _S((1<<24), "MS_STRICTATIME") _S((1<<25), "MS_LAZYTIME") _S((1<<26), "MS_SUBMOUNT") _S((1<<27), "MS_SNAP_STABLE") _S((1<<28), "MS_NOSEC") _S((1<<29), "MS_BORN") _S(MS_ACTIVE, "MS_ACTIVE") _S(MS_NOUSER, "MS_NOUSER") audit-userspace-4.0.5/auparse/netactiontab.h000066400000000000000000000017171501761310600211100ustar00rootroot00000000000000/* netactiontab.h -- * Copyright 2016 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/netfilter/xt_AUDIT.h */ _S(0, "ACCEPT") _S(1, "DROP") _S(2, "REJECT") audit-userspace-4.0.5/auparse/nfprototab.h000066400000000000000000000020501501761310600206020ustar00rootroot00000000000000/* nfprototab.h -- * Copyright 2011-14,2018 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/netfilter.h */ _S(0, "unspecified" ) _S(1, "inet" ) _S(2, "ipv4" ) _S(3, "arp" ) _S(5, "netdev" ) _S(7, "bridge" ) _S(10, "ipv6" ) _S(12, "decnet" ) audit-userspace-4.0.5/auparse/normalize-internal.h000066400000000000000000000073151501761310600222470ustar00rootroot00000000000000/* * normalize-internal.h * Copyright (c) 2016-18,21 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef NORMALIZE_INTERNAL #define NORMALIZE_INTERNAL #define NORM_ACCT_PRIV 0 #define NORM_ACCT_UNSET 4294967295U #define NORM_ACCT_MAX_SYS 1000 #define NORM_ACCT_MAX_USER 60000 /* * This is used for normalizing syscalls. It can determine * the action, object, obj_kind, and object attributes. */ #define NORM_UNKNOWN 0 #define NORM_FILE 1 #define NORM_FILE_CHATTR 2 #define NORM_FILE_CHPERM 3 #define NORM_FILE_CHOWN 4 #define NORM_FILE_LDMOD 5 #define NORM_FILE_UNLDMOD 6 #define NORM_FILE_DIR 7 #define NORM_FILE_MOUNT 8 #define NORM_FILE_RENAME 9 #define NORM_FILE_STAT 10 #define NORM_FILE_LNK 11 #define NORM_FILE_UMNT 12 #define NORM_FILE_DEL 13 #define NORM_FILE_TIME 14 #define NORM_EXEC 15 #define NORM_SOCKET_ACCEPT 16 #define NORM_SOCKET_BIND 17 #define NORM_SOCKET_CONN 18 #define NORM_SOCKET_RECV 19 #define NORM_SOCKET_SEND 20 #define NORM_PID 21 #define NORM_MAC 22 #define NORM_MAC_LOAD 23 #define NORM_MAC_CONFIG 24 #define NORM_MAC_ENFORCE 25 #define NORM_MAC_ERR 26 #define NORM_IPTABLES 27 #define NORM_PROMISCUOUS 28 #define NORM_UID 29 #define NORM_GID 30 #define NORM_SYSTEM_TIME 31 #define NORM_MAKE_DEV 32 #define NORM_SYSTEM_NAME 33 #define NORM_FILE_SYS_STAT 34 #define NORM_SYSTEM_MEMORY 35 #define NORM_SCHEDULER 36 #define NORM_AV 37 #define NORM_BPF 38 #define NORM_EV_LISTEN 39 #define NORM_SECURITY_POLICY 40 // This enum is used to map what the system objects are #define NORM_WHAT_UNKNOWN 0 #define NORM_WHAT_FIFO 1 #define NORM_WHAT_CHAR_DEV 2 #define NORM_WHAT_DIRECTORY 3 #define NORM_WHAT_BLOCK_DEV 4 #define NORM_WHAT_FILE 5 #define NORM_WHAT_LINK 6 #define NORM_WHAT_SOCKET 7 #define NORM_WHAT_PROCESS 8 #define NORM_WHAT_FIREWALL 9 #define NORM_WHAT_SERVICE 10 #define NORM_WHAT_ACCT 11 #define NORM_WHAT_USER_SESSION 12 #define NORM_WHAT_VM 13 #define NORM_WHAT_PRINTER 14 #define NORM_WHAT_SYSTEM 15 #define NORM_WHAT_AUDIT_RULE 16 #define NORM_WHAT_AUDIT_CONFIG 17 #define NORM_WHAT_SECURITY_POLICY 18 #define NORM_WHAT_FILESYSTEM 19 #define NORM_WHAT_MEMORY 20 #define NORM_WHAT_KEYSTROKES 21 #define NORM_WHAT_DEVICE 22 #define NORM_WHAT_SOFTWARE 23 #define NORM_WHAT_INTEGRITY_POLICY 24 // This enum is used to map events to what kind they are #define NORM_EVTYPE_UNKNOWN 0 #define NORM_EVTYPE_USERSPACE 1 #define NORM_EVTYPE_SYSTEM_SERVICES 2 #define NORM_EVTYPE_CONFIG 3 #define NORM_EVTYPE_TTY 4 #define NORM_EVTYPE_USER_ACCT 5 #define NORM_EVTYPE_USER_LOGIN 6 #define NORM_EVTYPE_AUDIT_DAEMON 7 #define NORM_EVTYPE_MAC_DECISION 8 #define NORM_EVTYPE_ANOMALY 9 #define NORM_EVTYPE_INTEGRITY 10 #define NORM_EVTYPE_ANOMALY_RESP 11 #define NORM_EVTYPE_MAC 12 #define NORM_EVTYPE_CRYPTO 13 #define NORM_EVTYPE_VIRT 14 #define NORM_EVTYPE_AUDIT_RULE 15 #define NORM_EVTYPE_DAC_DECISION 16 #define NORM_EVTYPE_GROUP_CHANGE 17 #define NORM_EVTYPE_AV_DECISION 18 #define NORM_EVTYPE_BPF 19 #endif audit-userspace-4.0.5/auparse/normalize-llist.c000066400000000000000000000037141501761310600215540ustar00rootroot00000000000000/* * normalize-llist.c - Minimal linked list library * Copyright (c) 2016-17 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include #include "normalize-llist.h" void cllist_create(cllist *l, void (*cleanup)(void *)) { l->head = NULL; l->cur = NULL; l->cleanup = cleanup; l->cnt = 0; } void cllist_clear(cllist *l) { data_node *nextnode; register data_node *current; if (l == NULL) return; current = l->head; while (current) { nextnode = current->next; if (l->cleanup) l->cleanup(current->data); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } data_node *cllist_next(cllist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } // Returns 0 on success and 1 on error int cllist_append(cllist *l, uint32_t num, void *data) { data_node *newnode; newnode = malloc(sizeof(data_node)); if (newnode == NULL) return 1; newnode->num = num; newnode->data = data; newnode->next = NULL; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } audit-userspace-4.0.5/auparse/normalize-llist.h000066400000000000000000000037631501761310600215650ustar00rootroot00000000000000/* * normalize-llist.h - Header file for normalize-llist.c * Copyright (c) 2016-17 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef NORMALIZE_LLIST_HEADER #define NORMALIZE_LLIST_HEADER #include "config.h" #include #include "private.h" /* This is the node of the linked list. Number & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _data_node { uint32_t num; // The number void *data; // Extra spot for data struct _data_node *next; // Next string node pointer } data_node; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { data_node *head; // List head data_node *cur; // Pointer to current node void (*cleanup)(void *); // Function to call when releasing memory unsigned int cnt; // How many items in this list } cllist; static inline void cllist_first(cllist *l) { l->cur = l->head; } static inline data_node *cllist_get_cur(const cllist *l) { return l->cur; } AUDIT_HIDDEN_START void cllist_create(cllist *l, void (*cleanup)(void *)); void cllist_clear(cllist* l); data_node *cllist_next(cllist *l); int cllist_append(cllist *l, uint32_t num, void *data); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/normalize.c000066400000000000000000001564271501761310600204410ustar00rootroot00000000000000/* normalize.c -- * Copyright 2016-18,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include #include #include #include #include #include #include "libaudit.h" #include "auparse.h" #include "internal.h" #include "normalize-llist.h" #include "normalize-internal.h" #include "gen_tables.h" #include "normalize_record_maps.h" #include "normalize_syscall_maps.h" #include "normalize_obj_kind_maps.h" #include "normalize_evtypetabs.h" /* * Field accessors. x is the new value, y is the variable * Layout is: 0xFFFF FFFF where first is record and second is field * Both record and field are 0 based. Simple records are always 0. Compound * records start at 0 and go up. */ #define UNSET 0xFFFFU #define get_record(y) ((y >> 16) & 0x0000FFFFU) #define set_record(y, x) (((x & 0x0000FFFFU) << 16) | (y & 0x0000FFFFU)) #define get_field(y) (y & 0x0000FFFFU) #define set_field(y, x) ((y & 0xFFFF0000U) | (x & 0x0000FFFFU)) #define is_unset(y) (get_record(y) == UNSET) #define D au->norm_data static int syscall_success; static value_t find_simple_object(auparse_state_t *au, int type); void init_normalizer(normalize_data *d) { d->evkind = NULL; d->session = set_record(0, UNSET); d->actor.primary = set_record(0, UNSET); d->actor.secondary = set_record(0, UNSET); d->actor.what = NULL; cllist_create(&d->actor.attr, NULL); d->action = NULL; d->thing.primary = set_record(0, UNSET); d->thing.secondary = set_record(0, UNSET); d->thing.two = set_record(0, UNSET); cllist_create(&d->thing.attr, NULL); d->thing.what = NORM_WHAT_UNKNOWN; d->results = set_record(0, UNSET); d->how = NULL; d->opt = NORM_OPT_ALL; d->key = set_record(0, UNSET); syscall_success = -1; } void clear_normalizer(normalize_data *d) { d->evkind = NULL; d->session = set_record(0, UNSET); d->actor.primary = set_record(0, UNSET); d->actor.secondary = set_record(0, UNSET); free((void *)d->actor.what); d->actor.what = NULL; cllist_clear(&d->actor.attr); free((void *)d->action); d->action = NULL; d->thing.primary = set_record(0, UNSET); d->thing.secondary = set_record(0, UNSET); d->thing.two = set_record(0, UNSET); cllist_clear(&d->thing.attr); d->thing.what = NORM_WHAT_UNKNOWN; d->results = set_record(0, UNSET); free((void *)d->how); d->how = NULL; d->opt = NORM_OPT_ALL; d->key = set_record(0, UNSET); syscall_success = -1; } static void set_system_subject_what(auparse_state_t *au) { D.actor.what = strdup("system"); } static void set_unknown_subject_what(auparse_state_t *au) { D.actor.what = strdup("unknown-acct"); } static unsigned int set_subject_what(auparse_state_t *au) { int uid = NORM_ACCT_UNSET - 1; int ftype = auparse_get_field_type(au); if (ftype == AUPARSE_TYPE_UID) uid = auparse_get_field_int(au); else { const char *n = auparse_get_field_name(au); if (n && strcmp(n, "acct") == 0) { const char *acct = auparse_interpret_field(au); if (acct) { // FIXME: Make this a LRU item struct passwd *pw = getpwnam(acct); if (pw) { uid = pw->pw_uid; goto check; } } } set_unknown_subject_what(au); return 1; } check: if (uid == NORM_ACCT_PRIV) D.actor.what = strdup("privileged-acct"); else if ((unsigned)uid == NORM_ACCT_UNSET) D.actor.what = strdup("unset-acct"); else if (uid < NORM_ACCT_MAX_SYS) D.actor.what = strdup("service-acct"); else if (uid < NORM_ACCT_MAX_USER) D.actor.what = strdup("user-acct"); else set_unknown_subject_what(au); return 0; } static unsigned int set_prime_subject(auparse_state_t *au, const char *str, unsigned int rnum) { if (auparse_find_field(au, str)) { D.actor.primary = set_record(0, rnum); D.actor.primary = set_field(D.actor.primary, auparse_get_field_num(au)); return 0; } return 1; } static unsigned int set_secondary_subject(auparse_state_t *au, const char *str, unsigned int rnum) { if (auparse_find_field(au, str)) { D.actor.secondary = set_record(0, rnum); D.actor.secondary = set_field(D.actor.secondary, auparse_get_field_num(au)); return set_subject_what(au); } return 1; } static unsigned int add_subj_attr(auparse_state_t *au, const char *str, unsigned int rnum) { value_t attr; if ((auparse_find_field(au, str))) { attr = set_record(0, rnum); attr = set_field(attr, auparse_get_field_num(au)); if (cllist_append(&D.actor.attr, attr, NULL)) return 1; return 0; } else auparse_goto_record_num(au, rnum); return 1; } static unsigned int set_prime_object(auparse_state_t *au, const char *str, unsigned int rnum) { if (auparse_find_field(au, str)) { D.thing.primary = set_record(0, rnum); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); return 0; } return 1; } static unsigned int set_prime_object2(auparse_state_t *au, const char *str, unsigned int adjust) { unsigned int rnum = 2 + adjust; auparse_goto_record_num(au, rnum); auparse_first_field(au); if (auparse_find_field(au, str)) { D.thing.two = set_record(0, rnum); D.thing.two = set_field(D.thing.two, auparse_get_field_num(au)); return 0; } return 1; } static unsigned int add_obj_attr(auparse_state_t *au, const char *str, unsigned int rnum) { value_t attr; if ((auparse_find_field(au, str))) { attr = set_record(0, rnum); attr = set_field(attr, auparse_get_field_num(au)); if (cllist_append(&D.thing.attr, attr, NULL)) return 1; return 0; } else auparse_goto_record_num(au, rnum); return 1; } static unsigned int add_session(auparse_state_t *au, unsigned int rnum) { if (auparse_find_field(au, "ses")) { D.session = set_record(0, rnum); D.session = set_field(D.session, auparse_get_field_num(au)); return 0; } else auparse_first_record(au); return 1; } static unsigned int set_results(auparse_state_t *au, unsigned int rnum) { if (auparse_find_field(au, "res")) { D.results = set_record(0, rnum); D.results = set_field(D.results, auparse_get_field_num(au)); return 0; } return 1; } static void syscall_subj_attr(auparse_state_t *au) { unsigned int rnum; auparse_first_record(au); do { rnum = auparse_get_record_num(au); if (auparse_get_type(au) == AUDIT_SYSCALL) { if (D.opt == NORM_OPT_NO_ATTRS) { add_session(au, rnum); return; } add_subj_attr(au, "ppid", rnum); add_subj_attr(au, "pid", rnum); add_subj_attr(au, "gid", rnum); add_subj_attr(au, "euid", rnum); add_subj_attr(au, "suid", rnum); add_subj_attr(au, "fsuid", rnum); add_subj_attr(au, "egid", rnum); add_subj_attr(au, "sgid", rnum); add_subj_attr(au, "fsgid", rnum); add_subj_attr(au, "tty", rnum); add_session(au, rnum); add_subj_attr(au, "subj", rnum); return; } } while (auparse_next_record(au) == 1); } static void collect_perm_obj2(auparse_state_t *au, const char *syscall) { const char *val; if (strcmp(syscall, "fchmodat") == 0) val = "a2"; else val = "a1"; auparse_first_record(au); if (auparse_find_field(au, val)) { D.thing.two = set_record(0, 0); D.thing.two = set_field(D.thing.two, auparse_get_field_num(au)); } } static void collect_own_obj2(auparse_state_t *au, const char *syscall) { const char *val; if (strcmp(syscall, "fchownat") == 0) val = "a2"; else val = "a1"; auparse_first_record(au); if (auparse_find_field(au, val)) { // if uid is -1, its not being changed, user group if (auparse_get_field_int(au) == -1 && errno == 0) auparse_next_field(au); D.thing.two = set_record(0, 0); D.thing.two = set_field(D.thing.two, auparse_get_field_num(au)); } } static void collect_id_obj2(auparse_state_t *au, const char *syscall) { unsigned int limit, cnt = 1; if (strcmp(syscall, "setuid") == 0) limit = 1; else if (strcmp(syscall, "setreuid") == 0) limit = 2; else if (strcmp(syscall, "setresuid") == 0) limit = 3; else if (strcmp(syscall, "setgid") == 0) limit = 1; else if (strcmp(syscall, "setregid") == 0) limit = 2; else if (strcmp(syscall, "setresgid") == 0) limit = 3; else return; // Shouldn't happen auparse_first_record(au); if (auparse_find_field(au, "a0")) { while (cnt <= limit) { const char *str = auparse_interpret_field(au); if ((strcmp(str, "unset") == 0) && errno == 0) { // Only move it if its safe to if (cnt < limit) { if (auparse_next_field(au) == 0) return; cnt++; } else return; } else break; } D.thing.two = set_record(0, 0); D.thing.two = set_field(D.thing.two, auparse_get_field_num(au)); } } static int collect_path_attrs(auparse_state_t *au) { value_t attr; unsigned int rnum = auparse_get_record_num(au); auparse_first_field(au); if (add_obj_attr(au, "mode", rnum)) return 1; // Failed opens don't have anything else // All the rest of the fields matter while ((auparse_next_field(au))) { attr = set_record(0, rnum); attr = set_field(attr, auparse_get_field_num(au)); if (cllist_append(&D.thing.attr, attr, NULL)) return 1; } return 0; } static void collect_cwd_attrs(auparse_state_t *au) { unsigned int rnum = auparse_get_record_num(au); add_obj_attr(au, "cwd", rnum); } static void collect_sockaddr_attrs(auparse_state_t *au) { unsigned int rnum = auparse_get_record_num(au); add_obj_attr(au, "saddr", rnum); } static void simple_file_attr(auparse_state_t *au) { int parent = 0; if (D.opt == NORM_OPT_NO_ATTRS) return; auparse_first_record(au); do { const char *f; int type = auparse_get_type(au); switch (type) { case AUDIT_PATH: f = auparse_find_field(au, "nametype"); if (f && strcmp(f, "PARENT") == 0) { if (parent == 0) parent = auparse_get_record_num(au); continue; } // First normal record is collected collect_path_attrs(au); return; break; case AUDIT_CWD: collect_cwd_attrs(au); break; case AUDIT_SOCKADDR: collect_sockaddr_attrs(au); break; } } while (auparse_next_record(au) == 1); // If we get here, path was never collected. Go back and get parent if (parent) { auparse_goto_record_num(au, parent); collect_path_attrs(au); } } static void set_file_object(auparse_state_t *au, int adjust) { const char *f; int parent = 0; unsigned int rnum; auparse_goto_record_num(au, 2 + adjust); auparse_first_field(au); // Now double check that we picked the right one. do { f = auparse_find_field(au, "nametype"); if (f) { if (strcmp(f, "PARENT")) break; if (parent == 0) parent = auparse_get_record_num(au); } } while (f && auparse_next_record(au) == 1); // Sometimes we only have the parent (failed open at dir permission) if (f == NULL) { if (parent == 0) return; auparse_goto_record_num(au, parent); auparse_first_field(au); rnum = parent; } else rnum = auparse_get_record_num(au); if (auparse_get_type(au) == AUDIT_PATH) { auparse_first_field(au); // Object set_prime_object(au, "name", rnum); f = auparse_find_field(au, "inode"); if (f) { D.thing.secondary = set_record(0, rnum); D.thing.secondary = set_field(D.thing.secondary, auparse_get_field_num(au)); } f = auparse_find_field(au, "mode"); if (f) { unsigned int mode; errno = 0; mode = strtoul(f, NULL, 8); if (errno == 0) { if (S_ISREG(mode)) D.thing.what = NORM_WHAT_FILE; else if (S_ISDIR(mode)) D.thing.what = NORM_WHAT_DIRECTORY; else if (S_ISCHR(mode)) D.thing.what = NORM_WHAT_CHAR_DEV; else if (S_ISBLK(mode)) D.thing.what = NORM_WHAT_BLOCK_DEV; else if (S_ISFIFO(mode)) D.thing.what = NORM_WHAT_FIFO; else if (S_ISLNK(mode)) D.thing.what = NORM_WHAT_LINK; else if (S_ISSOCK(mode)) D.thing.what = NORM_WHAT_SOCKET; } } } } static void set_socket_object(auparse_state_t *au) { auparse_goto_record_num(au, 1); auparse_first_field(au); set_prime_object(au, "saddr", 1); } /* This is only called processing syscall records */ static int set_program_obj(auparse_state_t *au) { auparse_first_record(au); int type = auparse_get_type(au); if (type == AUDIT_BPF) { if (auparse_find_field(au, "prog-id")) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } } else if (type == AUDIT_EVENT_LISTENER) { if (auparse_find_field(au, "nl-mcgrp")) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } } else if (type == AUDIT_MAC_POLICY_LOAD) { if (auparse_find_field(au, "lsm")) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } } else if (auparse_find_field(au, "exe")) { const char *exe = auparse_interpret_field(au); if ((strncmp(exe, "/usr/bin/python", 15) == 0) || (strncmp(exe, "/usr/bin/sh", 11) == 0) || (strncmp(exe, "/usr/bin/bash", 13) == 0) || (strncmp(exe, "/usr/bin/perl", 13) == 0)) { // comm should be the previous field int fnum; if ((fnum = auparse_get_field_num(au)) > 0) auparse_goto_field_num(au, fnum - 1); else auparse_first_record(au); auparse_find_field(au, "comm"); } D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); return 0; } return 1; } /* * This function is supposed to come up with the action and object for the * syscalls. */ static int normalize_syscall(auparse_state_t *au, const char *syscall) { int rc, tmp_objkind, objtype = NORM_UNKNOWN, ttype = 0, offset = 0; const char *act = NULL, *f; // cycle through all records and see what we have tmp_objkind = objtype; rc = auparse_first_record(au); while (rc == 1) { ttype = auparse_get_type(au); if (ttype == AUDIT_AVC) { // We want to go ahead with syscall to get objects tmp_objkind = NORM_MAC; break; } else if (ttype == AUDIT_SELINUX_ERR) { objtype = NORM_MAC_ERR; break; } else if (ttype == AUDIT_NETFILTER_CFG) { objtype = NORM_IPTABLES; break; } else if (ttype == AUDIT_ANOM_PROMISCUOUS) { objtype = NORM_PROMISCUOUS; break; } else if (ttype == AUDIT_KERN_MODULE) { objtype = NORM_FILE_LDMOD; break; } else if (ttype == AUDIT_MAC_POLICY_LOAD) { objtype = NORM_MAC_LOAD; break; } else if (ttype == AUDIT_MAC_STATUS) { objtype = NORM_MAC_ENFORCE; break; } else if (ttype == AUDIT_MAC_CONFIG_CHANGE) { objtype = NORM_MAC_CONFIG; break; } else if (ttype == AUDIT_FANOTIFY) { // We want to go ahead with syscall to get objects tmp_objkind = NORM_AV; break; } else if (ttype == AUDIT_TIME_INJOFFSET || ttype == AUDIT_TIME_ADJNTPVAL) { objtype = NORM_SYSTEM_TIME; break; } else if (ttype == AUDIT_BPF) { objtype = NORM_BPF; break; } else if (ttype == AUDIT_EVENT_LISTENER) { objtype = NORM_EV_LISTEN; break; } rc = auparse_next_record(au); } // lookup system call - it can be NULL if interpret_field failed. In // that case, the s2i call will fail and leave objtype untouched if (objtype == NORM_UNKNOWN) normalize_syscall_map_s2i(syscall, &objtype); // FIXME: Need to address: landlock_*, lsm_*, map_shadow_stack, pkey_*, // kexec_file_load, They likely need new NORM_* types. Also, these suggest // that NORM_WHAT_ may need some new types. switch (objtype) { case NORM_FILE: act = "opened-file"; set_file_object(au, 0); D.thing.what = NORM_WHAT_FILE; // this gets overridden simple_file_attr(au); break; case NORM_FILE_CHATTR: act = "changed-file-attributes-of"; D.thing.what = NORM_WHAT_FILE; // this gets overridden if (strcmp(syscall, "fsetxattr") == 0) offset = -1; set_file_object(au, offset); simple_file_attr(au); break; case NORM_FILE_CHPERM: act = "changed-file-permissions-of"; D.thing.what = NORM_WHAT_FILE; // this gets overridden if (strcmp(syscall, "fchmod") == 0) offset = -1; collect_perm_obj2(au, syscall); set_file_object(au, offset); simple_file_attr(au); break; case NORM_FILE_CHOWN: act = "changed-file-ownership-of"; D.thing.what = NORM_WHAT_FILE; // this gets overridden if (strcmp(syscall, "fchown") == 0) offset = -1; collect_own_obj2(au, syscall); set_file_object(au, offset); // FIXME: fchown has no cwd simple_file_attr(au); break; case NORM_FILE_LDMOD: act = "loaded-kernel-module"; D.thing.what = NORM_WHAT_FILE; auparse_goto_record_num(au, 1); set_prime_object(au, "name", 1);// FIXME:is this needed? break; case NORM_FILE_UNLDMOD: act = "unloaded-kernel-module"; D.thing.what = NORM_WHAT_FILE; // this gets overridden // set_file_object(au, 0); // simple_file_attr(au); break; case NORM_FILE_DIR: act = "created-directory"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_file_object(au, 1); // New dir is one after simple_file_attr(au); break; case NORM_FILE_MOUNT: act = "mounted"; // this gets overridden D.thing.what = NORM_WHAT_FILESYSTEM; if (syscall_success == 1) set_prime_object2(au, "name", 0); //The device is 1 after on success 0 on fail set_file_object(au, syscall_success); // We call this directly to make sure the right // PATH record is used. (There can be 4.) collect_path_attrs(au); break; case NORM_FILE_RENAME: act = "renamed"; D.thing.what = NORM_WHAT_FILE; // this gets overridden /* A sucessfull syscall from the rename family will provide * the following items: * 0 - new dir, in which the file will be located * 1 - old dir, in which the file was located * 2 - old name, the name of the original file * if the file was already present in the new dir: * 3 - removal of the new file * 4 - creation of the new file * otherwise: * 3 - creation of the new file */ // The 3rd record will always contain the name of the new file set_prime_object2(au, "name", 3); set_file_object(au, 2); // Thing renamed is 2 after simple_file_attr(au); break; case NORM_FILE_STAT: act = "checked-metadata-of"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_file_object(au, 0); simple_file_attr(au); break; case NORM_FILE_SYS_STAT: act = "checked-filesystem-metadata-of"; D.thing.what = NORM_WHAT_FILESYSTEM; // this gets overridden set_file_object(au, 0); simple_file_attr(au); break; case NORM_FILE_LNK: act = "symlinked"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_prime_object2(au, "name", 0); set_file_object(au, 2); simple_file_attr(au); break; case NORM_FILE_UMNT: act = "unmounted"; D.thing.what = NORM_WHAT_FILESYSTEM; // this gets overridden set_file_object(au, 0); simple_file_attr(au); break; case NORM_FILE_DEL: act = "deleted"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_file_object(au, 0); simple_file_attr(au); break; case NORM_FILE_TIME: act = "changed-timestamp-of"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_file_object(au, 0); simple_file_attr(au); break; case NORM_EXEC: act = "executed"; D.thing.what = NORM_WHAT_FILE; // this gets overridden set_file_object(au, 1); simple_file_attr(au); break; case NORM_SOCKET_ACCEPT: act = "accepted-connection-from"; D.thing.what = NORM_WHAT_SOCKET; set_socket_object(au); break; case NORM_SOCKET_BIND: act = "bound-socket"; D.thing.what = NORM_WHAT_SOCKET; set_socket_object(au); break; case NORM_SOCKET_CONN: act = "connected-to"; D.thing.what = NORM_WHAT_SOCKET; set_socket_object(au); break; case NORM_SOCKET_RECV: act = "received-from"; D.thing.what = NORM_WHAT_SOCKET; set_socket_object(au); break; case NORM_SOCKET_SEND: act = "sent-to"; D.thing.what = NORM_WHAT_SOCKET; set_socket_object(au); break; case NORM_PID: if (auparse_get_num_records(au) > 2) // FIXME: this has implications for object act = "killed-list-of-pids"; else act = "killed-pid"; auparse_goto_record_num(au, 1); auparse_first_field(au); f = auparse_find_field(au, "saddr"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } D.thing.what = NORM_WHAT_PROCESS; break; case NORM_MAC_LOAD: act = normalize_record_map_i2s(ttype); // FIXME: What is the object? D.thing.what = NORM_WHAT_SECURITY_POLICY; break; case NORM_MAC_CONFIG: act = normalize_record_map_i2s(ttype); f = auparse_find_field(au, "bool"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } D.thing.what = NORM_WHAT_SECURITY_POLICY; break; case NORM_MAC_ENFORCE: act = normalize_record_map_i2s(ttype); f = auparse_find_field(au, "enforcing"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } D.thing.what = NORM_WHAT_SECURITY_POLICY; break; case NORM_MAC_ERR: // FIXME: What could the object be? act = "caused-mac-policy-error"; // For now we'll call the obj_kind the system D.thing.what = NORM_WHAT_SYSTEM; break; case NORM_IPTABLES: act = "loaded-firewall-rule-to"; auparse_first_record(au); f = auparse_find_field(au, "table"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } D.thing.what = NORM_WHAT_FIREWALL; break; case NORM_PROMISCUOUS: auparse_first_record(au); f = auparse_find_field(au, "dev"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } f = auparse_find_field(au, "prom"); if (f) { int i = auparse_get_field_int(au); if (i == 0) act = "left-promiscuous-mode-on-device"; else act = "entered-promiscuous-mode-on-device"; } D.thing.what = NORM_WHAT_SOCKET; break; case NORM_UID: case NORM_GID: act = "changed-identity-of"; D.thing.what = NORM_WHAT_PROCESS; set_program_obj(au); if (D.how) { free((void *)D.how); D.how = strdup(syscall); } collect_id_obj2(au, syscall); break; case NORM_SYSTEM_TIME: act = "changed-system-time"; // TODO: can't think of an object for this one D.thing.what = NORM_WHAT_SYSTEM; break; case NORM_MAKE_DEV: set_file_object(au, 0); simple_file_attr(au); if (D.thing.what == NORM_WHAT_CHAR_DEV) act = "made-character-device"; else if (D.thing.what == NORM_WHAT_BLOCK_DEV) act = "made-block-device"; else act = "make-device"; break; case NORM_SYSTEM_NAME: act = "changed-system-name"; // TODO: can't think of an object for this one D.thing.what = NORM_WHAT_SYSTEM; break; case NORM_SYSTEM_MEMORY: act = "allocated-memory"; if (syscall_success == 1) { // If its not a mmap avc, we can use comm act = "allocated-memory-in"; auparse_first_record(au); f = auparse_find_field(au, "comm"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } } D.thing.what = NORM_WHAT_MEMORY; break; case NORM_SCHEDULER: act = "adjusted-scheduling-policy-of"; D.thing.what = NORM_WHAT_PROCESS; set_program_obj(au); if (D.how) { free((void *)D.how); D.how = strdup(syscall); } break; case NORM_BPF: auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) { const char *str = auparse_get_field_str(au); if (strcmp(str, "LOAD") == 0) act = "loaded-bpf-program"; else act = "unloaded-bpf-program"; } else act = "bpf-program"; D.thing.what = NORM_WHAT_PROCESS; set_program_obj(au); break; case NORM_EV_LISTEN: auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) { const char *str = auparse_get_field_str(au); if (strcmp(str, "connect") == 0) act = "connected-to"; else act = "disconnected-from"; } else act = "connected"; D.thing.what = NORM_WHAT_SOCKET; set_program_obj(au); break; case NORM_SECURITY_POLICY: act = "adjusted-security-policy-of"; D.thing.what = NORM_WHAT_PROCESS; set_program_obj(au); if (D.how) { free((void *)D.how); D.how = strdup(syscall); } break; default: { const char *k; rc = auparse_first_record(au); k = auparse_find_field(au, "key"); if (k && strcmp(k, "(null)")) { act = "triggered-audit-rule"; D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field( D.thing.primary, auparse_get_field_num(au)); } else act = "triggered-unknown-audit-rule"; D.thing.what = NORM_WHAT_AUDIT_RULE; } break; } // We put the AVC back after gathering the object information if (tmp_objkind == NORM_MAC) act = "accessed-mac-policy-controlled-object"; else if (tmp_objkind == NORM_AV) act = "accessed-policy-controlled-file"; if (act) D.action = strdup(act); return 0; } static const char *normalize_determine_evkind(int type) { int kind; switch (type) { case AUDIT_USER_AUTH ... AUDIT_USER_ACCT: case AUDIT_CRED_ACQ ... AUDIT_USER_END: case AUDIT_USER_CHAUTHTOK ... AUDIT_CRED_REFR: case AUDIT_USER_LOGIN ... AUDIT_USER_LOGOUT: case AUDIT_LOGIN: kind = NORM_EVTYPE_USER_LOGIN; break; case AUDIT_GRP_AUTH: case AUDIT_CHGRP_ID: kind = NORM_EVTYPE_GROUP_CHANGE; break; case AUDIT_USER_MGMT: case AUDIT_ADD_USER ...AUDIT_DEL_GROUP: case AUDIT_GRP_MGMT ... AUDIT_GRP_CHAUTHTOK: case AUDIT_ACCT_LOCK ... AUDIT_ACCT_UNLOCK: kind = NORM_EVTYPE_USER_ACCT; break; case AUDIT_KERNEL: case AUDIT_SYSTEM_BOOT ... AUDIT_SERVICE_STOP: kind = NORM_EVTYPE_SYSTEM_SERVICES; break; case AUDIT_USYS_CONFIG: case AUDIT_CONFIG_CHANGE: case AUDIT_NETFILTER_CFG: case AUDIT_FEATURE_CHANGE: case AUDIT_TIME_INJOFFSET: case AUDIT_TIME_ADJNTPVAL: case AUDIT_USER_DEVICE: case AUDIT_SOFTWARE_UPDATE: kind = NORM_EVTYPE_CONFIG; break; case AUDIT_SECCOMP: kind = NORM_EVTYPE_DAC_DECISION; break; case AUDIT_TEST ... AUDIT_TRUSTED_APP: case AUDIT_USER_CMD: case AUDIT_CHUSER_ID: kind = NORM_EVTYPE_USERSPACE; break; case AUDIT_USER_TTY: case AUDIT_TTY: kind = NORM_EVTYPE_TTY; break; case AUDIT_EVENT_LISTENER: case AUDIT_FIRST_DAEMON ... AUDIT_LAST_DAEMON: kind = NORM_EVTYPE_AUDIT_DAEMON; break; case AUDIT_USER_SELINUX_ERR: case AUDIT_USER_AVC: case AUDIT_APPARMOR_ALLOWED ... AUDIT_APPARMOR_DENIED: case AUDIT_APPARMOR_ERROR: case AUDIT_AVC ... AUDIT_AVC_PATH: kind = NORM_EVTYPE_MAC_DECISION; break; case AUDIT_INTEGRITY_FIRST_MSG ... AUDIT_INTEGRITY_LAST_MSG: case AUDIT_ANOM_RBAC_INTEGRITY_FAIL: // Aide sends this kind = NORM_EVTYPE_INTEGRITY; break; case AUDIT_FIRST_KERN_ANOM_MSG ... AUDIT_LAST_KERN_ANOM_MSG: case AUDIT_FIRST_ANOM_MSG ... AUDIT_ANOM_RBAC_FAIL: case AUDIT_ANOM_CRYPTO_FAIL ... AUDIT_LAST_ANOM_MSG: kind = NORM_EVTYPE_ANOMALY; break; case AUDIT_FIRST_ANOM_RESP ... AUDIT_LAST_ANOM_RESP: kind = NORM_EVTYPE_ANOMALY_RESP; break; case AUDIT_MAC_POLICY_LOAD ... AUDIT_LAST_SELINUX: case AUDIT_AA ... AUDIT_APPARMOR_AUDIT: case AUDIT_APPARMOR_HINT ... AUDIT_APPARMOR_STATUS: case AUDIT_FIRST_USER_LSPP_MSG ... AUDIT_LAST_USER_LSPP_MSG: kind = NORM_EVTYPE_MAC; break; case AUDIT_FIRST_KERN_CRYPTO_MSG ... AUDIT_LAST_KERN_CRYPTO_MSG: case AUDIT_FIRST_CRYPTO_MSG ... AUDIT_LAST_CRYPTO_MSG: kind = NORM_EVTYPE_CRYPTO; break; case AUDIT_FIRST_VIRT_MSG ... AUDIT_LAST_VIRT_MSG: kind = NORM_EVTYPE_VIRT; break; case AUDIT_SYSCALL ... AUDIT_SOCKETCALL: case AUDIT_SOCKADDR ... AUDIT_MQ_GETSETATTR: case AUDIT_FD_PAIR ... AUDIT_OBJ_PID: case AUDIT_BPRM_FCAPS ... AUDIT_NETFILTER_PKT: case AUDIT_URINGOP: kind = NORM_EVTYPE_AUDIT_RULE; break; case AUDIT_FANOTIFY: kind = NORM_EVTYPE_AV_DECISION; break; case AUDIT_BPF: kind = NORM_EVTYPE_BPF; break; default: kind = NORM_EVTYPE_UNKNOWN; } return evtype_i2s(kind); } const char *find_config_change_object(auparse_state_t *au) { const char *f; // Check if its an audit rule auparse_first_record(au); f = auparse_find_field(au, "key"); if (f) { const char *str = auparse_get_field_str(au); if (str && strcmp(str, "(null)")) return f; } // Next lets find the individual objects being set auparse_first_record(au); f = auparse_find_field(au, "audit_enabled"); if (f) return f; auparse_first_record(au); f = auparse_find_field(au, "audit_pid"); if (f) return f; auparse_first_record(au); f = auparse_find_field(au, "audit_backlog_limit"); if (f) return f; auparse_first_record(au); f = auparse_find_field(au, "audit_failure"); if (f) return f; auparse_first_record(au); f = auparse_find_field(au, "actions"); // seccomp-logging if (f) return f; auparse_first_record(au); f = auparse_find_field(au, "list"); // If nothing else, the list if (f) return f; return NULL; } static int normalize_compound(auparse_state_t *au) { const char *f, *syscall = NULL; int rc, recno, otype, type; otype = type = auparse_get_type(au); // All compound events have a syscall record, find it. After this // loop, type should be syscall, and otype is the original type. // Traditionally, the first record is the purpose of the event and // the syscall is added on next to support/enhance information content. if (type != AUDIT_SYSCALL) { do { // If we go off the end without finding a syscall // record, don't parse corrupt events if (auparse_next_record(au) < 0) return 1; type = auparse_get_type(au); } while (type && type != AUDIT_SYSCALL); } if (!type) return 1; // Determine the kind of event using original event type D.evkind = normalize_determine_evkind(otype); if (type == AUDIT_SYSCALL) { recno = auparse_get_record_num(au); f = auparse_find_field(au, "syscall"); if (f) { f = auparse_interpret_field(au); if (f) syscall = strdup(f); } // Results f = auparse_find_field(au, "success"); if (f) { const char *str = auparse_get_field_str(au); if (strcmp(str, "no") == 0) syscall_success = 0; else syscall_success = 1; D.results = set_record(0, recno); D.results = set_field(D.results, auparse_get_field_num(au)); } else { rc = auparse_goto_record_num(au, recno); if (rc != 1) { free((void *)syscall); return 1; } auparse_first_field(au); } // Subject - primary if (set_prime_subject(au, "auid", recno)) { rc = auparse_goto_record_num(au, recno); if (rc != 1) { free((void *)syscall); return 1; } auparse_first_field(au); } // Subject - alias, uid comes before auid if (set_secondary_subject(au, "uid", recno)) { rc = auparse_goto_record_num(au, recno); if (rc != 1) { free((void *)syscall); return 1; } auparse_first_field(au); } // Subject attributes syscall_subj_attr(au); // how auparse_first_field(au); f = auparse_find_field(au, "exe"); if (f) { const char *exe = auparse_interpret_field(au); D.how = strdup(exe); if (D.how == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); free((void *)syscall); return 1; } if ((strncmp(D.how, "/usr/bin/python", 15) == 0) || (strncmp(D.how, "/usr/bin/sh", 11) == 0) || (strncmp(D.how, "/usr/bin/bash", 13) == 0) || (strncmp(D.how, "/usr/bin/perl", 13) == 0)) { int fnum; rc = 0; // Comm should be the previous field if ((fnum = auparse_get_field_num(au)) > 0) rc = auparse_goto_field_num(au,fnum-1); if (rc == 0) auparse_first_record(au); f = auparse_find_field(au, "comm"); if (f) { free((void *)D.how); exe = auparse_interpret_field(au); D.how = strdup(exe); } } } else { rc = auparse_goto_record_num(au, recno); if (rc != 1) { free((void *)syscall); return 1; } auparse_first_field(au); } f = auparse_find_field(au, "key"); if (f) { const char *k = auparse_get_field_str(au); if (strcmp(k, "(null)")) { // We only collect real keys D.key = set_record(0, recno); D.key = set_field(D.key, auparse_get_field_num(au)); } } // No error repositioning will be done because nothing // below uses fields. // action & object if (otype == AUDIT_ANOM_LINK) { const char *act = normalize_record_map_i2s(otype); if (act) D.action = strdup(act); // FIXME: AUDIT_ANOM_LINK needs an object } else if (otype == AUDIT_CONFIG_CHANGE) { auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) { value_t o; // Fix the action D.action = strdup(auparse_interpret_field(au)); // Next fix the object o = find_simple_object(au, AUDIT_CONFIG_CHANGE); D.thing.primary = o; } } else { normalize_syscall(au, syscall); if (otype == AUDIT_MAC_POLICY_LOAD) set_program_obj(au); } } free((void *)syscall); return 0; } static value_t find_simple_object(auparse_state_t *au, int type) { value_t o = set_record(0, UNSET); const char *f = NULL; auparse_first_field(au); switch (type) { case AUDIT_SERVICE_START: case AUDIT_SERVICE_STOP: f = auparse_find_field(au, "unit"); D.thing.what = NORM_WHAT_SERVICE; break; case AUDIT_SYSTEM_RUNLEVEL: f = auparse_find_field(au, "new-level"); D.thing.what = NORM_WHAT_SYSTEM; break; case AUDIT_USER_ROLE_CHANGE: f = auparse_find_field(au, "selected-context"); D.thing.what = NORM_WHAT_USER_SESSION; break; case AUDIT_ROLE_ASSIGN: case AUDIT_ROLE_REMOVE: case AUDIT_USER_MGMT: case AUDIT_ACCT_LOCK: case AUDIT_ACCT_UNLOCK: case AUDIT_ADD_USER: case AUDIT_DEL_USER: case AUDIT_ADD_GROUP: case AUDIT_DEL_GROUP: case AUDIT_GRP_MGMT: f = auparse_find_field(au, "id"); if (f == NULL) { auparse_first_record(au); f = auparse_find_field(au, "acct"); } D.thing.what = NORM_WHAT_ACCT; break; case AUDIT_USER_START: case AUDIT_USER_END: case AUDIT_USER_ERR: case AUDIT_USER_LOGIN: case AUDIT_USER_LOGOUT: f = auparse_find_field(au, "terminal"); D.thing.what = NORM_WHAT_USER_SESSION; break; case AUDIT_USER_AUTH: case AUDIT_USER_ACCT: case AUDIT_CRED_ACQ: case AUDIT_CRED_REFR: case AUDIT_CRED_DISP: case AUDIT_USER_CHAUTHTOK: case AUDIT_GRP_CHAUTHTOK: case AUDIT_ANOM_LOGIN_FAILURES: case AUDIT_ANOM_LOGIN_TIME: case AUDIT_ANOM_LOGIN_SESSIONS: case AUDIT_ANOM_LOGIN_LOCATION: f = auparse_find_field(au, "acct"); D.thing.what = NORM_WHAT_USER_SESSION; break; case AUDIT_ANOM_EXEC: case AUDIT_USER_CMD: f = auparse_find_field(au, "cmd"); D.thing.what = NORM_WHAT_PROCESS; break; case AUDIT_USER_TTY: case AUDIT_TTY: auparse_first_record(au); f = auparse_find_field(au, "data"); D.thing.what = NORM_WHAT_KEYSTROKES; break; case AUDIT_USER_DEVICE: auparse_first_record(au); f = auparse_find_field(au, "device"); D.thing.what = NORM_WHAT_KEYSTROKES; break; case AUDIT_SOFTWARE_UPDATE: auparse_first_record(au); f = auparse_find_field(au, "sw"); D.thing.what = NORM_WHAT_SOFTWARE; break; case AUDIT_VIRT_MACHINE_ID: f = auparse_find_field(au, "vm"); D.thing.what = NORM_WHAT_VM; break; case AUDIT_VIRT_RESOURCE: f = auparse_find_field(au, "resrc"); D.thing.what = NORM_WHAT_VM; break; case AUDIT_VIRT_CONTROL: f = auparse_find_field(au, "op"); D.thing.what = NORM_WHAT_VM; break; case AUDIT_LABEL_LEVEL_CHANGE: f = auparse_find_field(au, "printer"); D.thing.what = NORM_WHAT_PRINTER; break; case AUDIT_CONFIG_CHANGE: f = find_config_change_object(au); D.thing.what = NORM_WHAT_AUDIT_CONFIG; break; case AUDIT_MAC_CONFIG_CHANGE: f = auparse_find_field(au, "bool"); D.thing.what = NORM_WHAT_SECURITY_POLICY; break; case AUDIT_MAC_STATUS: f = auparse_find_field(au, "enforcing"); D.thing.what = NORM_WHAT_SECURITY_POLICY; break; // These deal with policy, not sure about object yet case AUDIT_MAC_POLICY_LOAD: case AUDIT_LABEL_OVERRIDE: case AUDIT_DEV_ALLOC ... AUDIT_USER_MAC_CONFIG_CHANGE: D.thing.what = NORM_WHAT_SECURITY_POLICY; break; case AUDIT_USER: f = auparse_find_field(au, "addr"); // D.thing.what = NORM_WHAT_? break; case AUDIT_USYS_CONFIG: f = auparse_find_field(au, "op"); if (f) { free((void *)D.action); D.action = strdup(auparse_interpret_field(au)); f = NULL; } D.thing.what = NORM_WHAT_SYSTEM; break; case AUDIT_CRYPTO_KEY_USER: f = auparse_find_field(au, "fp"); D.thing.what = NORM_WHAT_USER_SESSION; break; case AUDIT_CRYPTO_SESSION: f = auparse_find_field(au, "addr"); D.thing.what = NORM_WHAT_USER_SESSION; break; case AUDIT_ANOM_RBAC_INTEGRITY_FAIL: f = auparse_find_field(au, "hostname"); D.thing.what = NORM_WHAT_FILESYSTEM; break; default: break; } if (f) { o = set_record(0, 0); o = set_field(o, auparse_get_field_num(au)); } return o; } static value_t find_simple_obj_secondary(auparse_state_t *au, int type) { value_t o = set_record(0, UNSET); const char *f = NULL; // FIXME: maybe pass flag indicating if this is needed auparse_first_field(au); switch (type) { case AUDIT_CRYPTO_SESSION: f = auparse_find_field(au, "rport"); break; case AUDIT_SOFTWARE_UPDATE: f = auparse_find_field(au, "sw_type"); break; default: break; } if (f) { o = set_record(0, 0); o = set_field(o, auparse_get_field_num(au)); } return o; } static value_t find_simple_obj_primary2(auparse_state_t *au, int type) { value_t o = set_record(0, UNSET); const char *f = NULL; // FIXME: maybe pass flag indicating if this is needed auparse_first_field(au); switch (type) { case AUDIT_VIRT_CONTROL: f = auparse_find_field(au, "vm"); break; case AUDIT_VIRT_RESOURCE: f = auparse_find_field(au, "vm"); break; case AUDIT_SOFTWARE_UPDATE: f = auparse_find_field(au, "root_dir"); break; default: break; } if (f) { o = set_record(0, 0); o = set_field(o, auparse_get_field_num(au)); } return o; } static void collect_simple_subj_attr(auparse_state_t *au) { if (D.opt == NORM_OPT_NO_ATTRS) return; auparse_first_record(au); add_subj_attr(au, "pid", 0); // Just pass 0 since simple is 1 record add_subj_attr(au, "subj", 0); } static void collect_userspace_subj_attr(auparse_state_t *au, int type) { if (D.opt == NORM_OPT_NO_ATTRS) return; // Just pass 0 since simple is 1 record add_subj_attr(au, "hostname", 0); add_subj_attr(au, "addr", 0); // Some events have the terminal as the object - skip for them if (type != AUDIT_USER_START && type != AUDIT_USER_END && type != AUDIT_USER_ERR) add_subj_attr(au, "terminal", 0); } static int normalize_simple(auparse_state_t *au) { const char *f, *act = NULL; int type = auparse_get_type(au); // Some older OS do not have PROCTITLE records if (type == AUDIT_SYSCALL) return normalize_compound(au); // Determine the kind of event D.evkind = normalize_determine_evkind(type); // This is for events that follow: // auid, (op), (uid), stuff if (type == AUDIT_CONFIG_CHANGE || type == AUDIT_FEATURE_CHANGE || type == AUDIT_SECCOMP || type == AUDIT_ANOM_ABEND || type == AUDIT_ANOM_PROMISCUOUS) { // Subject - primary set_prime_subject(au, "auid", 0); // Session add_session(au, 0); // Subject attrs collect_simple_subj_attr(au); // action if (type == AUDIT_CONFIG_CHANGE) { auparse_first_field(au); f = auparse_find_field(au, "op"); if (f) { const char *str = auparse_interpret_field(au); if (*str == '"') str++; if (strncmp(str, "add_rule", 8) == 0) { D.action = strdup("added-audit-rule"); D.thing.primary = find_simple_object(au, type); } else if (strncmp(str,"remove_rule",11) == 0){ D.action = strdup("deleted-audit-rule"); D.thing.primary = find_simple_object(au, type); } else goto map; } else goto map; } else { // This assigns action for feature_change, seccomp, // and anom_abend map: act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); if (type == AUDIT_CONFIG_CHANGE) D.thing.primary = find_simple_object(au, type); auparse_first_record(au); } // object if (type == AUDIT_FEATURE_CHANGE) { // Subject - secondary auparse_first_field(au); if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); // how f = auparse_find_field(au, "exe"); if (f) { const char *sig = auparse_interpret_field(au); D.how = strdup(sig); } // object set_prime_object(au, "feature", 0); D.thing.what = NORM_WHAT_SYSTEM; } if (type == AUDIT_SECCOMP) { // Subject - secondary auparse_first_field(au); if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); // how f = auparse_find_field(au, "exe"); if (f) { const char *sig = auparse_interpret_field(au); D.how = strdup(sig); } // Object if (set_prime_object(au, "syscall", 0)) auparse_first_record(au); D.thing.what = NORM_WHAT_PROCESS; // Results f = auparse_find_field(au, "code"); if (f) { D.results = set_record(0, 0); D.results = set_field(D.results, auparse_get_field_num(au)); } return 0; } if (type == AUDIT_ANOM_ABEND) { // Subject - secondary auparse_first_field(au); if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); //object if (set_prime_object(au, "exe", 0)) auparse_first_record(au); D.thing.what = NORM_WHAT_PROCESS; // how f = auparse_find_field(au, "sig"); if (f) { const char *sig = auparse_interpret_field(au); D.how = strdup(sig); } } if (type == AUDIT_ANOM_PROMISCUOUS) { auparse_first_field(au); set_prime_object(au, "dev", 0); set_secondary_subject(au, "uid", 0); D.thing.what = NORM_WHAT_SOCKET; } // Results set_results(au, 0); return 0; } // This one is atypical and originates from the kernel if (type == AUDIT_LOGIN) { // Secondary if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); // Subject attrs collect_simple_subj_attr(au); // Subject if (set_prime_subject(au, "old-auid", 0)) auparse_first_record(au); // Object if (set_prime_object(au, "auid", 0)) auparse_first_record(au); D.thing.what = NORM_WHAT_USER_SESSION; // Session add_session(au, 0); // Results set_results(au, 0); // action act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); // How - currently missing return 0; } // NETFILTER_CFG is atypical if (type == AUDIT_NETFILTER_CFG) { // Subject attrs collect_simple_subj_attr(au); // how f = auparse_find_field(au, "comm"); if (f) { const char *sig = auparse_interpret_field(au); D.how = strdup(sig); } D.action = strdup("loaded-firewall-rule-to"); auparse_first_record(au); f = auparse_find_field(au, "table"); if (f) { D.thing.primary = set_record(0, auparse_get_record_num(au)); D.thing.primary = set_field(D.thing.primary, auparse_get_field_num(au)); } set_system_subject_what(au); D.thing.what = NORM_WHAT_FIREWALL; return 0; } /* This one is also atypical and comes from the kernel */ if (type == AUDIT_AVC) { // how f = auparse_find_field(au, "comm"); if (f) { const char *sig = auparse_interpret_field(au); D.how = strdup(sig); } else auparse_first_record(au); // Subject set_prime_subject(au, "scontext", 0); set_unknown_subject_what(au); auparse_first_record(au); // Object if (D.opt == NORM_OPT_ALL) { // We will only collect this when everything is asked // for because it messes up text format otherwise set_prime_object(au, "tcontext", 0); auparse_first_record(au); } // Ideally we would choose tclass D.thing.what = NORM_WHAT_UNKNOWN; // action act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); // find the denial auparse_first_record(au); f = auparse_find_field(au, "seresult"); if (f) { D.results = set_record(0, 0); D.results = set_field(D.results, auparse_get_field_num(au)); } // This is slim pickings without a syscall record return 0; } /* Daemon events are atypical because they never transit the kernel */ if (type >= AUDIT_FIRST_DAEMON && type < AUDIT_LAST_DAEMON) { // Subject - primary set_prime_subject(au, "auid", 0); // Secondary - optional if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); // Session - optional if (add_session(au, 0)) auparse_first_record(au); // Subject attrs collect_simple_subj_attr(au); free((void *)D.actor.what); D.actor.what = strdup("auditd"); // action act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); // Object type D.thing.what = NORM_WHAT_SERVICE; // How start:init, everything else:signal if (type == AUDIT_DAEMON_START) D.how = strdup("init"); else if (type < AUDIT_DAEMON_ACCEPT && type != AUDIT_DAEMON_ABORT) D.how = strdup("signal"); // Results set_results(au, 0); return 0; } // BPF events are atypical if (type == AUDIT_BPF) { set_system_subject_what(au); auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) { const char *str = auparse_get_field_str(au); if (strcmp(str, "LOAD") == 0) act = "loaded-bpf-program"; else act = "unloaded-bpf-program"; } else act = "bpf-program"; D.action = strdup(act); D.thing.what = NORM_WHAT_PROCESS; set_program_obj(au); return 0; } // LISTENER events are atypical if (type == AUDIT_EVENT_LISTENER) { // Subject - primary set_prime_subject(au, "auid", 0); // Secondary - optional auparse_first_record(au); set_secondary_subject(au, "uid", 0); // Session auparse_first_record(au); add_session(au, 0); // Subject attrs collect_simple_subj_attr(au); auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) { const char *str = auparse_get_field_str(au); if (strcmp(str, "connect") == 0) act = "connected-to"; else act = "disconnected-from"; } else act = "connected"; D.action = strdup(act); set_program_obj(au); D.thing.what = NORM_WHAT_SOCKET; // How auparse_first_record(au); f = auparse_find_field(au, "exe"); if (f) { const char *exe = auparse_interpret_field(au); D.how = strdup(exe); } // Results auparse_first_record(au); set_results(au, 0); return 0; } // Labeled networking events are atypical if (type >= AUDIT_MAC_UNLBL_ALLOW && type <= AUDIT_LAST_SELINUX) { // Subject - primary set_prime_subject(au, "auid", 0); // We don't have a secondary subject, so set it to auid set_subject_what(au); // Session add_session(au, 0); // Subject attrs add_subj_attr(au, "subj", 0); // action if (type == AUDIT_MAC_UNLBL_ALLOW) { f = auparse_find_field(au, "unlbl_accept"); if (f) { if (auparse_get_field_int(au) == 1) act = "is-allowing-unlabeled-network-traffic"; else act = "is-disallowing-unlabeled-network-traffic"; } else auparse_first_record(au); } else act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); if (type == AUDIT_MAC_MAP_ADD || type == AUDIT_MAC_MAP_DEL) { if (set_prime_object(au, "nlbl_domain", 0)) auparse_first_record(au); } // Object type D.thing.what = NORM_WHAT_SECURITY_POLICY; // Results set_results(au, 0); return 0; } // This is for events that follow: // uid, auid, ses, res, find_simple_object // // USER_LOGIN is different in locating the subject because if they // fail login, they are not quite in the system to have an auid. if (type == AUDIT_USER_LOGIN) { // Subject - primary if (set_prime_subject(au, "id", 0)) { auparse_first_record(au); if (set_prime_subject(au, "acct", 0) == 0) set_subject_what(au); } else // If id found, set the subjkind set_subject_what(au); auparse_first_record(au); } else { // Subject - alias, uid comes before auid if (set_secondary_subject(au, "uid", 0)) auparse_first_record(au); // Subject - primary set_prime_subject(au, "auid", 0); } // Session add_session(au, 0); // Subject attrs collect_simple_subj_attr(au); if ((type >= AUDIT_FIRST_USER_MSG && type < AUDIT_LAST_USER_MSG) || (type >= AUDIT_FIRST_USER_MSG2 && type < AUDIT_LAST_USER_MSG2)) collect_userspace_subj_attr(au, type); // Results if (type != AUDIT_USER_AVC) set_results(au, 0); else { // find the denial auparse_first_record(au); f = auparse_find_field(au, "seresult"); if (f) { D.results = set_record(0, 0); D.results = set_field(D.results, auparse_get_field_num(au)); } // Subject auparse_first_record(au); set_prime_subject(au, "scontext", 0); // Object if (D.opt == NORM_OPT_ALL) { // We will only collect this when everything is asked // for because it messes up text format otherwise auparse_first_record(au); set_prime_object(au, "tcontext", 0); } } // action if (type == AUDIT_USER_DEVICE) { auparse_first_record(au); f = auparse_find_field(au, "op"); if (f) act = f; } if (act == NULL) act = normalize_record_map_i2s(type); if (act) D.action = strdup(act); // object if (type != AUDIT_USER_AVC) { auparse_first_record(au); D.thing.primary = find_simple_object(au, type); D.thing.secondary = find_simple_obj_secondary(au, type); D.thing.two = find_simple_obj_primary2(au, type); // object attrs - rare on simple events if (D.opt == NORM_OPT_ALL) { if (type == AUDIT_USER_DEVICE) { add_obj_attr(au, "uuid", 0); } else if (type == AUDIT_SOFTWARE_UPDATE) { auparse_first_record(au); add_obj_attr(au, "key_enforce", 0); add_obj_attr(au, "gpg_res", 0); } } } // how if (type == AUDIT_SYSTEM_BOOT) { D.thing.what = NORM_WHAT_SYSTEM; f = auparse_find_field(au, "exe"); if (f) { const char *exe = auparse_interpret_field(au); D.how = strdup(exe); } return 0; } else if (type == AUDIT_SYSTEM_SHUTDOWN) { D.thing.what = NORM_WHAT_SERVICE; f = auparse_find_field(au, "exe"); if (f) { const char *exe = auparse_interpret_field(au); D.how = strdup(exe); } return 0; } auparse_first_record(au); if (type == AUDIT_ANOM_EXEC) { f = auparse_find_field(au, "terminal"); if (f) { const char *term = auparse_interpret_field(au); D.how = strdup(term); } return 0; } if (type == AUDIT_TTY) { f = auparse_find_field(au, "comm"); if (f) { const char *comm = auparse_interpret_field(au); D.how = strdup(comm); } return 0; } f = auparse_find_field(au, "exe"); if (f) { const char *exe = auparse_interpret_field(au); D.how = strdup(exe); if (D.how == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); return 1; } if ((strncmp(D.how, "/usr/bin/python", 15) == 0) || (strncmp(D.how, "/usr/bin/sh", 11) == 0) || (strncmp(D.how, "/usr/bin/bash", 13) == 0) || (strncmp(D.how, "/usr/bin/perl", 13) == 0)) { // comm should be the previous field if its there at all int fnum; if ((fnum = auparse_get_field_num(au)) > 0) auparse_goto_field_num(au, fnum - 1); else auparse_first_record(au); f = auparse_find_field(au, "comm"); if (f) { free((void *)D.how); exe = auparse_interpret_field(au); D.how = strdup(exe); } } } return 0; } /* * This is the main entry point for the normalization. This function * will analyze the current event to pick out the important pieces. */ int auparse_normalize(auparse_state_t *au, normalize_option_t opt) { int rc; unsigned num; auparse_first_record(au); num = auparse_get_num_records(au); // Reset cursor - no idea what we are being handed auparse_first_record(au); clear_normalizer(&D); D.opt = opt; // If we have more than one record in the event its a syscall based // event. Otherwise its a simple event with all pieces in the same // record. if (num > 1) rc = normalize_compound(au); else rc = normalize_simple(au); // Reset the cursor auparse_first_record(au); return rc; } /* * This function positions the internal cursor to the record and field that * the location refers to. * Returns: < 0 error, 0 uninitialized, 1 == success */ static int seek_field(auparse_state_t *au, value_t location) { int record, field, rc; if (is_unset(location)) return 0; record = get_record(location); field = get_field(location); rc = auparse_goto_record_num(au, record); if (rc != 1) return -1; rc = auparse_goto_field_num(au, field); if (rc != 1) return -2; return 1; } const char *auparse_normalize_get_event_kind(const auparse_state_t *au) { return D.evkind; } int auparse_normalize_session(auparse_state_t *au) { return seek_field(au, D.session); } int auparse_normalize_subject_primary(auparse_state_t *au) { return seek_field(au, D.actor.primary); } int auparse_normalize_subject_secondary(auparse_state_t *au) { return seek_field(au, D.actor.secondary); } const char *auparse_normalize_subject_kind(const auparse_state_t *au) { return D.actor.what; } // Returns: -1 = error, 0 uninitialized, 1 == success int auparse_normalize_subject_first_attribute(auparse_state_t *au) { if (D.actor.attr.cnt) { data_node *n; cllist_first(&D.actor.attr); n = cllist_get_cur(&D.actor.attr); if (n) return seek_field(au, n->num); } return 0; } // Returns: -1 = error, 0 uninitialized, 1 == success int auparse_normalize_subject_next_attribute(auparse_state_t *au) { if (D.actor.attr.cnt) { data_node *n; n = cllist_next(&D.actor.attr); if (n) return seek_field(au, n->num); } return 0; } const char *auparse_normalize_get_action(const auparse_state_t *au) { return D.action; } int auparse_normalize_object_primary(auparse_state_t *au) { return seek_field(au, D.thing.primary); } int auparse_normalize_object_secondary(auparse_state_t *au) { return seek_field(au, D.thing.secondary); } int auparse_normalize_object_primary2(auparse_state_t *au) { return seek_field(au, D.thing.two); } // Returns: -1 = error, 0 uninitialized, 1 == success int auparse_normalize_object_first_attribute(auparse_state_t *au) { if (D.thing.attr.cnt) { data_node *n; cllist_first(&D.thing.attr); n = cllist_get_cur(&D.thing.attr); if (n) return seek_field(au, n->num); } return 0; } // Returns: -1 = error, 0 uninitialized, 1 == success int auparse_normalize_object_next_attribute(auparse_state_t *au) { if (D.thing.attr.cnt) { data_node *n; n = cllist_next(&D.thing.attr); if (n) return seek_field(au, n->num); } return 0; } const char *auparse_normalize_object_kind(const auparse_state_t *au) { return normalize_obj_kind_map_i2s(D.thing.what); } int auparse_normalize_get_results(auparse_state_t *au) { return seek_field(au, D.results); } const char *auparse_normalize_how(const auparse_state_t *au) { return D.how; } int auparse_normalize_key(auparse_state_t *au) { return seek_field(au, D.key); } audit-userspace-4.0.5/auparse/normalize_evtypetab.h000066400000000000000000000033131501761310600225120ustar00rootroot00000000000000/* normalize_evtypetab.h -- * Copyright 2017,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "normalize-internal.h" _S(NORM_EVTYPE_UNKNOWN, "unknown" ) _S(NORM_EVTYPE_USERSPACE, "user-space" ) _S(NORM_EVTYPE_SYSTEM_SERVICES, "system-services" ) _S(NORM_EVTYPE_CONFIG, "configuration" ) _S(NORM_EVTYPE_TTY, "TTY" ) _S(NORM_EVTYPE_USER_ACCT, "user-account" ) _S(NORM_EVTYPE_USER_LOGIN, "user-login" ) _S(NORM_EVTYPE_AUDIT_DAEMON, "audit-daemon" ) _S(NORM_EVTYPE_MAC_DECISION, "mac-decision" ) _S(NORM_EVTYPE_ANOMALY, "anomaly" ) _S(NORM_EVTYPE_INTEGRITY, "integrity" ) _S(NORM_EVTYPE_ANOMALY_RESP, "anomaly-response") _S(NORM_EVTYPE_MAC, "mac" ) _S(NORM_EVTYPE_CRYPTO, "crypto" ) _S(NORM_EVTYPE_VIRT, "virt" ) _S(NORM_EVTYPE_AUDIT_RULE, "audit-rule" ) _S(NORM_EVTYPE_DAC_DECISION, "dac-decision" ) _S(NORM_EVTYPE_GROUP_CHANGE, "group-change" ) _S(NORM_EVTYPE_AV_DECISION, "av-decision" ) _S(NORM_EVTYPE_BPF, "bpf-program" ) audit-userspace-4.0.5/auparse/normalize_obj_kind_map.h000066400000000000000000000034601501761310600231260ustar00rootroot00000000000000/* * normalize_obj_kind_map.h * Copyright (c) 2016-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "normalize-internal.h" _S(NORM_WHAT_UNKNOWN, "unknown") _S(NORM_WHAT_FIFO, "fifo") _S(NORM_WHAT_CHAR_DEV, "character-device") _S(NORM_WHAT_DIRECTORY, "directory") _S(NORM_WHAT_BLOCK_DEV, "block-device") _S(NORM_WHAT_FILE, "file") _S(NORM_WHAT_FILESYSTEM, "file-system") _S(NORM_WHAT_LINK, "symlink") _S(NORM_WHAT_SOCKET, "socket") _S(NORM_WHAT_PROCESS, "process") _S(NORM_WHAT_FIREWALL, "firewall") _S(NORM_WHAT_SERVICE, "service") _S(NORM_WHAT_ACCT, "account") _S(NORM_WHAT_USER_SESSION, "user-session") _S(NORM_WHAT_VM, "virtual-machine") _S(NORM_WHAT_PRINTER, "printer") _S(NORM_WHAT_SYSTEM, "system") _S(NORM_WHAT_AUDIT_RULE, "admin-defined-rule") _S(NORM_WHAT_AUDIT_CONFIG, "audit-config") _S(NORM_WHAT_SECURITY_POLICY, "security-policy") _S(NORM_WHAT_MEMORY, "memory") _S(NORM_WHAT_KEYSTROKES, "keystrokes") _S(NORM_WHAT_DEVICE, "device") _S(NORM_WHAT_SOFTWARE, "software") _S(NORM_WHAT_INTEGRITY_POLICY, "integrity-policy") //_S(, "") audit-userspace-4.0.5/auparse/normalize_record_map.h000066400000000000000000000155171501761310600226330ustar00rootroot00000000000000/* * normalize_record_map.h * Copyright (c) 2016-18,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "libaudit.h" _S(AUDIT_USER, "sent-message") _S(AUDIT_LOGIN, "changed-login-id-to") _S(AUDIT_USER_AUTH, "authenticated") _S(AUDIT_USER_ACCT, "was-authorized") _S(AUDIT_USER_MGMT, "modified-user-account") _S(AUDIT_CRED_ACQ, "acquired-credentials") _S(AUDIT_CRED_DISP, "disposed-credentials") _S(AUDIT_USER_START, "started-session") _S(AUDIT_USER_END, "ended-session") _S(AUDIT_USER_AVC, "accessed-mac-policy-controlled-object") _S(AUDIT_USER_CHAUTHTOK, "changed-password") _S(AUDIT_USER_ERR, "caused-account-error") _S(AUDIT_CRED_REFR, "refreshed-credentials") _S(AUDIT_USYS_CONFIG, "changed-configuration") _S(AUDIT_USER_LOGIN, "logged-in") _S(AUDIT_USER_LOGOUT, "logged-out") _S(AUDIT_ADD_USER, "added-user-account") _S(AUDIT_DEL_USER, "deleted-user-account") _S(AUDIT_ADD_GROUP, "added-group-account-to") _S(AUDIT_DEL_GROUP, "deleted-group-account-from") _S(AUDIT_DAC_CHECK, "access-result") _S(AUDIT_CHGRP_ID, "changed-group") _S(AUDIT_TEST, "sent-test") _S(AUDIT_TRUSTED_APP, "unknown") _S(AUDIT_USER_SELINUX_ERR, "access-error") _S(AUDIT_USER_CMD, "ran-command") _S(AUDIT_USER_TTY, "typed") _S(AUDIT_CHUSER_ID, "changed-user-id") _S(AUDIT_GRP_AUTH, "authenticated-to-group") _S(AUDIT_SYSTEM_BOOT, "booted-system") _S(AUDIT_SYSTEM_SHUTDOWN, "shutdown-system") _S(AUDIT_SYSTEM_RUNLEVEL, "changed-to-runlevel") _S(AUDIT_SERVICE_START, "started-service") _S(AUDIT_SERVICE_STOP, "stopped-service") _S(AUDIT_GRP_MGMT, "modified-group-account") _S(AUDIT_GRP_CHAUTHTOK, "changed-group-password") _S(AUDIT_MAC_CHECK, "mac-permission") _S(AUDIT_ACCT_LOCK, "locked-account") _S(AUDIT_ACCT_UNLOCK, "unlocked-account") _S(AUDIT_USER_DEVICE, "configured-device") _S(AUDIT_SOFTWARE_UPDATE, "installed-software") _S(AUDIT_DAEMON_START, "started-audit") _S(AUDIT_DAEMON_END, "shutdown-audit") _S(AUDIT_DAEMON_ABORT, "aborted-auditd-startup") _S(AUDIT_DAEMON_CONFIG, "changed-auditd-configuration") _S(AUDIT_DAEMON_RECONFIG, "reconfigured-auditd") _S(AUDIT_DAEMON_ROTATE, "rotated-audit-logs") _S(AUDIT_DAEMON_RESUME, "resumed-audit-logging") _S(AUDIT_DAEMON_ACCEPT, "remote-audit-connected") _S(AUDIT_DAEMON_CLOSE, "remote-audit-disconnected") _S(AUDIT_DAEMON_ERR, "audit-error") _S(AUDIT_CONFIG_CHANGE, "changed-audit-configuration") //_S(AUDIT_KERNEL_OTHER,"") _S(AUDIT_TTY, "typed") //_S(AUDIT_NETFILTER_PKT,"") //_S(AUDIT_NETFILTER_CFG,"") _S(AUDIT_SECCOMP, "called-seccomp-controlled-syscall") _S(AUDIT_FEATURE_CHANGE, "changed-audit-feature") //_S(AUDIT_REPLACE,"") _S(AUDIT_KERN_MODULE, "loaded-kernel-module") _S(AUDIT_FANOTIFY, "accessed-policy-controlled-file") //_S(AUDIT_BPF, "") //_S(AUDIT_EVENT_LISTENER, "") //_S(AUDIT_OPENAT2, "") _S(AUDIT_URINGOP, "io_uring-operation") _S(AUDIT_AVC, "accessed-mac-policy-controlled-object") _S(AUDIT_MAC_POLICY_LOAD, "loaded-selinux-policy") _S(AUDIT_MAC_STATUS, "changed-selinux-enforcement-to") _S(AUDIT_MAC_CONFIG_CHANGE, "changed-selinux-boolean") //_S(AUDIT_MAC_UNLBL_ALLOW, "") _S(AUDIT_MAC_MAP_ADD, "added-mac-network-domain-mapping-to") _S(AUDIT_MAC_MAP_DEL, "deleted-mac-network-domain-mapping-from") _S(AUDIT_ANOM_PROMISCUOUS, "changed-socket-promiscuous-mode") _S(AUDIT_ANOM_ABEND, "crashed-program") _S(AUDIT_ANOM_LINK, "used-suspcious-link") _S(AUDIT_ANOM_CREAT, "created-suspicious-file") //_S(AUDIT_INTEGRITY_DATA,"") //_S(AUDIT_INTEGRITY_METADATA,"") //_S(AUDIT_INTEGRITY_STATUS,"") //_S(AUDIT_INTEGRITY_HASH,"") //_S(AUDIT_INTEGRITY_PCR,"") //_S(AUDIT_INTEGRITY_RULE,"") //_S(AUDIT_INTEGRITY_EVM_XATTR,"") _S(AUDIT_KERNEL, "initialized-audit-subsystem") _S(AUDIT_ANOM_LOGIN_FAILURES, "failed-log-in-too-many-times-to") _S(AUDIT_ANOM_LOGIN_TIME, "attempted-log-in-during-unusual-hour-to") _S(AUDIT_ANOM_LOGIN_SESSIONS, "opened-too-many-sessions-to") //_S(AUDIT_ANOM_LOGIN_ACCT, "") _S(AUDIT_ANOM_LOGIN_LOCATION, "attempted-log-in-from-unusual-place-to") //_S(AUDIT_ANOM_MAX_DAC, "") //_S(AUDIT_ANOM_MAX_MAC, "") //_S(AUDIT_ANOM_AMTU_FAIL, "") //_S(AUDIT_ANOM_RBAC_FAIL, "") _S(AUDIT_ANOM_RBAC_INTEGRITY_FAIL, "tested-file-system-integrity-of") //_S(AUDIT_ANOM_CRYPTO_FAIL, "") //_S(AUDIT_ANOM_ACCESS_FS, "") _S(AUDIT_ANOM_EXEC, "attempted-execution-of-forbidden-program") //_S(AUDIT_ANOM_MK_EXEC, "") //_S(AUDIT_ANOM_ADD_ACCT, "") //_S(AUDIT_ANOM_DEL_ACCT, "") //_S(AUDIT_ANOM_MOD_ACCT, "") //_S(AUDIT_ANOM_ROOT_TRANS, "") //_S(AUDIT_RESP_ANOMALY, "") //_S(AUDIT_RESP_ALERT, "") //_S(AUDIT_RESP_KILL_PROC, "") //_S(AUDIT_RESP_TERM_ACCESS, "") //_S(AUDIT_RESP_ACCT_REMOTE, "") //_S(AUDIT_RESP_ACCT_LOCK_TIMED, "") //_S(AUDIT_RESP_ACCT_UNLOCK_TIMED, "") //_S(AUDIT_RESP_ACCT_LOCK, "") //_S(AUDIT_RESP_TERM_LOCK, "") //_S(AUDIT_RESP_SEBOOL, "") //_S(AUDIT_RESP_EXEC, "") //_S(AUDIT_RESP_SINGLE, "") //_S(AUDIT_RESP_HALT, "") _S(AUDIT_USER_ROLE_CHANGE, "changed-role-to") _S(AUDIT_ROLE_ASSIGN, "assigned-user-role-to") _S(AUDIT_ROLE_REMOVE, "removed-use-role-from") _S(AUDIT_LABEL_OVERRIDE, "overrode-label-of") _S(AUDIT_LABEL_LEVEL_CHANGE, "modified-level-of") //_S(AUDIT_USER_LABELED_EXPORT, "") //_S(AUDIT_USER_UNLABELED_EXPORT, "") //_S(AUDIT_DEV_ALLOC, "") //_S(AUDIT_DEV_DEALLOC, "") _S(AUDIT_FS_RELABEL, "relabeled-filesystem") _S(AUDIT_USER_MAC_POLICY_LOAD, "loaded-mac-policy") _S(AUDIT_ROLE_MODIFY, "modified-role") _S(AUDIT_USER_MAC_CONFIG_CHANGE, "changed-mac-configuration") _S(AUDIT_USER_MAC_STATUS, "changed-selinux-enforcement-to") //_S(AUDIT_CRYPTO_TEST_USER, "") //_S(AUDIT_CRYPTO_PARAM_CHANGE_USER, "") _S(AUDIT_CRYPTO_LOGIN, "crypto-officer-logged-in") _S(AUDIT_CRYPTO_LOGOUT, "crypto-officer-logged-out") _S(AUDIT_CRYPTO_KEY_USER, "negotiated-crypto-key") //_S(AUDIT_CRYPTO_FAILURE_USER, "") //_S(AUDIT_CRYPTO_REPLAY_USER, "") _S(AUDIT_CRYPTO_SESSION, "started-crypto-session") //_S(AUDIT_CRYPTO_IKE_SA, "") //_S(AUDIT_CRYPTO_IPSEC_SA, "") _S(AUDIT_VIRT_CONTROL, "issued-vm-control") _S(AUDIT_VIRT_RESOURCE, "assigned-vm-resource") _S(AUDIT_VIRT_MACHINE_ID, "assigned-vm-id") _S(AUDIT_VIRT_INTEGRITY_CHECK, "checked-integrity-of") _S(AUDIT_VIRT_CREATE, "created-vm-image") _S(AUDIT_VIRT_DESTROY, "deleted-vm-image") _S(AUDIT_VIRT_MIGRATE_IN, "migrated-vm-from") _S(AUDIT_VIRT_MIGRATE_OUT, "migrated-vm-to") //_S(,"") audit-userspace-4.0.5/auparse/normalize_syscall_map.h000066400000000000000000000105201501761310600230140ustar00rootroot00000000000000/* * normalize_syscall_map.h * Copyright (c) 2016-17,2021-24 Red Hat Inc. * All Rights Reserved. * * 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "normalize-internal.h" _S(NORM_FILE_STAT, "access") _S(NORM_FILE_STAT, "faccessat") _S(NORM_FILE_STAT, "faccessat2") _S(NORM_FILE_CHPERM, "chmod") _S(NORM_FILE_CHPERM, "fchmod") _S(NORM_FILE_CHPERM, "fchmodat") _S(NORM_FILE_CHPERM, "fchmodat2") _S(NORM_FILE_CHOWN, "chown") _S(NORM_FILE_CHOWN, "fchown") _S(NORM_FILE_CHOWN, "fchownat") _S(NORM_FILE_CHOWN, "fchownat2") _S(NORM_FILE_CHOWN, "lchown") _S(NORM_FILE_LDMOD, "finit_module") _S(NORM_FILE_LDMOD, "init_module") _S(NORM_FILE_UNLDMOD, "delete_module") _S(NORM_FILE_CHATTR, "setxattr") _S(NORM_FILE_CHATTR, "setxattrat") _S(NORM_FILE_CHATTR, "fsetxattr") _S(NORM_FILE_CHATTR, "lsetxattr") _S(NORM_FILE_CHATTR, "mount_setattr") _S(NORM_FILE_DIR, "mkdir") _S(NORM_FILE_DIR, "mkdirat") _S(NORM_FILE_MOUNT, "fsconfig") _S(NORM_FILE_MOUNT, "fsmount") _S(NORM_FILE_MOUNT, "fsopen") _S(NORM_FILE_MOUNT, "fspick") _S(NORM_FILE_MOUNT, "mount") _S(NORM_FILE_MOUNT, "move_mount") _S(NORM_FILE_STAT, "newfstatat") _S(NORM_FILE_STAT, "stat") _S(NORM_FILE_STAT, "fstat") _S(NORM_FILE_STAT, "lstat") _S(NORM_FILE_STAT, "stat64") _S(NORM_FILE_STAT, "statx") _S(NORM_FILE_SYS_STAT, "statfs") _S(NORM_FILE_SYS_STAT, "fstatfs") _S(NORM_FILE_SYS_STAT, "statmount") _S(NORM_FILE, "creat") _S(NORM_FILE, "fallocate") _S(NORM_FILE, "truncate") _S(NORM_FILE, "ftruncate") _S(NORM_FILE, "memfd_create") _S(NORM_FILE, "memfd_secret") _S(NORM_FILE, "open") _S(NORM_FILE, "openat") _S(NORM_FILE, "openat2") _S(NORM_FILE, "readlink") _S(NORM_FILE, "readlinkat") _S(NORM_FILE, "open_by_handle_at") _S(NORM_FILE, "pidfd_getfd") _S(NORM_FILE_CHATTR, "removexattr") _S(NORM_FILE_CHATTR, "removexattrat") _S(NORM_FILE_CHATTR, "fremovexattr") _S(NORM_FILE_CHATTR, "lremovexattr") _S(NORM_FILE_RENAME, "rename") _S(NORM_FILE_RENAME, "renameat") _S(NORM_FILE_RENAME, "renameat2") _S(NORM_FILE_DEL, "rmdir") _S(NORM_FILE_LNK, "symlink") _S(NORM_FILE_LNK, "symlinkat") _S(NORM_FILE_UMNT, "umount") _S(NORM_FILE_UMNT, "umount2") _S(NORM_FILE_DEL, "unlink") _S(NORM_FILE_DEL, "unlinkat") _S(NORM_FILE_TIME, "utime") _S(NORM_FILE_TIME, "utimes") _S(NORM_FILE_TIME, "futimesat") _S(NORM_FILE_TIME, "utimensat") _S(NORM_EXEC, "execve") _S(NORM_EXEC, "execveat") _S(NORM_SOCKET_ACCEPT, "accept") _S(NORM_SOCKET_ACCEPT, "accept4") _S(NORM_SOCKET_BIND, "bind") _S(NORM_SOCKET_CONN, "connect") _S(NORM_SOCKET_RECV, "recvfrom") _S(NORM_SOCKET_RECV, "recvmsg") _S(NORM_SOCKET_SEND, "sendmsg") _S(NORM_SOCKET_SEND, "sendto") _S(NORM_PID, "kill") _S(NORM_PID, "tkill") _S(NORM_PID, "tgkill") _S(NORM_UID, "setuid") _S(NORM_UID, "seteuid") _S(NORM_UID, "setfsuid") _S(NORM_UID, "setreuid") _S(NORM_UID, "setresuid") _S(NORM_GID, "setgid") _S(NORM_GID, "setegid") _S(NORM_GID, "setfsgid") _S(NORM_GID, "setregid") _S(NORM_GID, "setresgid") _S(NORM_SYSTEM_TIME, "settimeofday") _S(NORM_SYSTEM_TIME, "clock_settime") _S(NORM_SYSTEM_TIME, "clock_settime64") _S(NORM_SYSTEM_TIME, "stime") _S(NORM_SYSTEM_TIME, "adjtimex") _S(NORM_MAKE_DEV, "mknod") _S(NORM_MAKE_DEV, "mknodat") _S(NORM_SYSTEM_NAME, "sethostname") _S(NORM_SYSTEM_NAME, "setdomainname") _S(NORM_SYSTEM_MEMORY, "mmap") _S(NORM_SYSTEM_MEMORY, "brk") _S(NORM_SYSTEM_MEMORY, "map_shadow_stack") _S(NORM_SCHEDULER, "sched_setparam") _S(NORM_SCHEDULER, "sched_setscheduler") _S(NORM_SCHEDULER, "sched_setattr") _S(NORM_SECURITY_POLICY, "landlock_create_ruleset") _S(NORM_SECURITY_POLICY, "landlock_add_rule") _S(NORM_SECURITY_POLICY, "landlock_restrict_self") _S(NORM_SECURITY_POLICY, "lsm_set_self_attr") _S(NORM_SECURITY_POLICY, "mseal") audit-userspace-4.0.5/auparse/nvlist.c000066400000000000000000000103721501761310600177440ustar00rootroot00000000000000/* * nvlist.c - Minimal linked list library for name-value pairs * Copyright (c) 2006-07,2016,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include "nvlist.h" #include "interpret.h" #include "auparse-idata.h" static inline void alloc_array(nvlist *l) { l->array = calloc(NFIELDS, sizeof(nvnode)); l->size = NFIELDS; } void nvlist_create(nvlist *l) { if (l) { alloc_array(l); l->cur = 0; l->cnt = 0; l->record = NULL; l->end = NULL; } } nvnode *nvlist_next(nvlist *l) { // Since cur will be incremented, check for 1 less that total if (l->cnt && l->cur < (l->cnt - 1)) { l->cur++; return &l->array[l->cur]; } return NULL; } // 0 on success and 1 on error int nvlist_append(nvlist *l, const nvnode *node) { if (node->name == NULL) return 1; if (l->array == NULL) alloc_array(l); if (l->cnt == l->size) { nvnode* tmp; tmp = realloc(l->array, l->size * sizeof(nvnode) * 2); if (tmp != NULL) { l->array = tmp; memset(l->array + l->size, 0, sizeof(nvnode) * l->size); l->size = l->size * 2; } else return 1; } nvnode *newnode = &l->array[l->cnt]; newnode->name = node->name; newnode->val = node->val; newnode->interp_val = NULL; newnode->item = l->cnt; // make newnode current l->cur = l->cnt; l->cnt++; return 0; } /* * Its less code to make a fixup than a new append. */ void nvlist_interp_fixup(const nvlist *l) { nvnode* node = &l->array[l->cur]; node->interp_val = node->val; node->val = NULL; } nvnode *nvlist_goto_rec(nvlist *l, unsigned int i) { if (i < l->cnt) { l->cur = i; return &l->array[l->cur]; } return NULL; } /* * This function will start at current index and scan for a name */ int nvlist_find_name(nvlist *l, const char *name) { unsigned int i = l->cur; register nvnode *node; if (l->cnt == 0) return 0; do { node = &l->array[i]; if (node->name && strcmp(node->name, name) == 0) { l->cur = i; return 1; } i++; } while (i < l->cnt); return 0; } extern int interp_adjust_type(int rtype, const char *name, const char *val); int nvlist_get_cur_type(rnode *r) { nvlist *l = &r->nv; nvnode *node = &l->array[l->cur]; return auparse_interp_adjust_type(r->type, node->name, node->val); } const char *nvlist_interp_cur_val(rnode *r, auparse_esc_t escape_mode) { nvlist *l = &r->nv; if (l->cnt == 0) return NULL; nvnode *node = &l->array[l->cur]; if (node->interp_val) return node->interp_val; return do_interpret(r, escape_mode); } // This function determines if a chunk of memory is part of the parsed up // record. If it is, do not free it since it gets free'd at the very end. // NOTE: This function causes invalid-pointer-pair errors with ASAN static inline int not_in_rec_buf(nvlist *l, const char *ptr) { if (ptr >= l->record && ptr < l->end) return 0; return 1; } // free_interp does not apply to thing coming from interpretation_list void nvlist_clear(nvlist *l, int free_interp) { unsigned int i = 0; register nvnode *current; while (i < l->cnt) { current = &l->array[i]; if (free_interp) { free(current->interp_val); // A couple items are not in parsed up list. // These all come from the aup_list_append path. if (not_in_rec_buf(l, current->name)) { // seperms & key values are strdup'ed if (not_in_rec_buf(l, current->val)) free(current->val); free(current->name); } } i++; } free((void *)l->record); free(l->array); l->array = NULL; l->size = 0; l->record = NULL; l->end = NULL; l->cur = 0; l->cnt = 0; } audit-userspace-4.0.5/auparse/nvlist.h000066400000000000000000000043441501761310600177530ustar00rootroot00000000000000/* * nvlist.h - Header file for nvlist.c * Copyright (c) 2006-07,2016,2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef NVLIST_HEADER #define NVLIST_HEADER #include "config.h" #include "private.h" #include #include "rnode.h" #include "ellist.h" static inline unsigned int nvlist_get_cnt(const nvlist *l) { return l->cnt; } static inline void nvlist_first(nvlist *l) { l->cur = 0; } static inline nvnode *nvlist_get_cur(const nvlist *l) { return &l->array[l->cur]; } static inline const char *nvlist_get_cur_name(const nvlist *l) {if (l->cnt) { nvnode *node = &l->array[l->cur]; return node->name; } else return NULL;} static inline const char *nvlist_get_cur_val(const nvlist *l) {if (l->cnt) { nvnode *node = &l->array[l->cur]; return node->val; } else return NULL;} static inline const char *nvlist_get_cur_val_interp(const nvlist *l) {if (l->cnt) { nvnode *node = &l->array[l->cur]; return node->interp_val; } else return NULL;} AUDIT_HIDDEN_START void nvlist_create(nvlist *l); void nvlist_clear(nvlist *l, int free_interp); nvnode *nvlist_next(nvlist *l); int nvlist_get_cur_type(rnode *r); const char *nvlist_interp_cur_val(rnode *r, auparse_esc_t escape_mode); int nvlist_append(nvlist *l, const nvnode *node); void nvlist_interp_fixup(const nvlist *l); /* Given a numeric index, find that record. */ nvnode *nvlist_goto_rec(nvlist *l, unsigned int i); /* Given a name, find that record */ int nvlist_find_name(nvlist *l, const char *name); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/open-flagtab.h000066400000000000000000000025731501761310600207750ustar00rootroot00000000000000/* open-flagtab.h -- * Copyright 2007,2012-14 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/fcntl.h */ // Handled in the code: _S(00, "O_RDONLY" ) _S(01, "O_WRONLY" ) _S(02, "O_RDWR" ) _S(0100, "O_CREAT") _S(0200, "O_EXCL" ) _S(0400, "O_NOCTTY" ) _S(01000, "O_TRUNC" ) _S(02000, "O_APPEND" ) _S(04000, "O_NONBLOCK" ) _S(010000, "O_DSYNC" ) _S(020000, "O_ASYNC" ) _S(040000, "O_DIRECT" ) _S(0200000, "O_DIRECTORY" ) _S(0400000, "O_NOFOLLOW" ) _S(01000000, "O_NOATIME" ) _S(02000000, "O_CLOEXEC") _S(04000000, "__O_SYNC") _S(010000000, "O_PATH") _S(020000000, "__O_TMPFILE") audit-userspace-4.0.5/auparse/openat2-resolvetab.h000066400000000000000000000021261501761310600221440ustar00rootroot00000000000000/* openat2-resolvetab.h -- * Copyright 2021 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Richard Guy Briggs * Location: include/uapi/linux/openat2.h */ _S(0x01, "RESOLVE_NO_XDEV" ) _S(0x02, "RESOLVE_NO_MAGICLINKS" ) _S(0x04, "RESOLVE_NO_SYMLINKS" ) _S(0x08, "RESOLVE_BENEATH" ) _S(0x10, "RESOLVE_IN_ROOT" ) _S(0x20, "RESOLVE_CACHED" ) audit-userspace-4.0.5/auparse/persontab.h000066400000000000000000000034531501761310600204310ustar00rootroot00000000000000/* persontab.h -- * Copyright 2012-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/personality.h */ _S(0x0000, "PER_LINUX") _S(0x0000 | ADDR_LIMIT_32BIT, "PER_LINUX_32BIT") _S(0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, "PER_SVR4") _S(0x0002 | STICKY_TIMEOUTS | SHORT_INODE, "PER_SVR3") _S(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS | SHORT_INODE, "PER_SCOSVR3") _S(0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, "PER_OSR5") _S(0x0004 | STICKY_TIMEOUTS | SHORT_INODE, "PER_WYSEV386") _S(0x0005 | STICKY_TIMEOUTS, "PER_ISCR4") _S(0x0006, "PER_BSD") _S(0x0006 | STICKY_TIMEOUTS, "PER_SUNOS") _S(0x0007 | STICKY_TIMEOUTS | SHORT_INODE, "PER_XENIX") _S(0x0008, "PER_LINUX32") _S(0x0008 | ADDR_LIMIT_3GB, "PER_LINUX32_3GB") _S(0x0009 | STICKY_TIMEOUTS, "PER_IRIX32") _S(0x000a | STICKY_TIMEOUTS, "PER_IRIXN32") _S(0x000b | STICKY_TIMEOUTS, "PER_IRIX64") _S(0x000c, "PER_RISCOS") _S(0x000d | STICKY_TIMEOUTS, "PER_SOLARIS") _S(0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, "PER_UW7") _S(0x000f, "PER_OSF4") _S(0x0010, "PER_HPUX") audit-userspace-4.0.5/auparse/pktoptnametab.h000066400000000000000000000030241501761310600212770ustar00rootroot00000000000000/* pktoptnametab.h -- * Copyright 2013-14,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/if_packet.h */ _S(1, "PACKET_ADD_MEMBERSHIP") _S(2, "PACKET_DROP_MEMBERSHIP") _S(3, "PACKET_RECV_OUTPUT") _S(5, "PACKET_RX_RING") _S(6, "PACKET_STATISTICS") _S(7, "PACKET_COPY_THRESH") _S(8, "PACKET_AUXDATA") _S(9, "PACKET_ORIGDEV") _S(10, "PACKET_VERSION") _S(11, "PACKET_HDRLEN") _S(12, "PACKET_RESERVE") _S(13, "PACKET_TX_RING") _S(14, "PACKET_LOSS") _S(15, "PACKET_VNET_HDR") _S(16, "PACKET_TX_TIMESTAMP") _S(17, "PACKET_TIMESTAMP") _S(18, "PACKET_FANOUT") _S(19, "PACKET_TX_HAS_OFF") _S(20, "PACKET_QDISC_BYPASS") _S(21, "PACKET_ROLLOVER_STATS") _S(22, "PACKET_FANOUT_DATA") _S(23, "PACKET_IGNORE_OUTGOING") _S(24, "PACKET_VNET_HDR_SZ") audit-userspace-4.0.5/auparse/prctl-opt-tab.h000066400000000000000000000052741501761310600211270ustar00rootroot00000000000000/* prctl-opt-tab.h -- * Copyright 2013-16,2018,2020-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/prctl.h */ _S(1, "PR_SET_PDEATHSIG") _S(2, "PR_GET_PDEATHSIG") _S(3, "PR_GET_DUMPABLE") _S(4, "PR_SET_DUMPABLE") _S(5, "PR_GET_UNALIGN") _S(6, "PR_SET_UNALIGN") _S(7, "PR_GET_KEEPCAPS") _S(8, "PR_SET_KEEPCAPS") _S(9, "PR_GET_FPEMU") _S(10, "PR_SET_FPEMU") _S(11, "PR_GET_FPEXC") _S(12, "PR_SET_FPEXC") _S(13, "PR_GET_TIMING") _S(14, "PR_SET_TIMING") _S(15, "PR_SET_NAME") _S(16, "PR_GET_NAME") _S(19, "PR_GET_ENDIAN") _S(20, "PR_SET_ENDIAN") _S(21, "PR_GET_SECCOMP") _S(22, "PR_SET_SECCOMP") _S(23, "PR_CAPBSET_READ") _S(24, "PR_CAPBSET_DROP") _S(25, "PR_GET_TSC") _S(26, "PR_SET_TSC") _S(27, "PR_GET_SECUREBITS") _S(28, "PR_SET_SECUREBITS") _S(29, "PR_SET_TIMERSLACK") _S(30, "PR_GET_TIMERSLACK") _S(31, "PR_TASK_PERF_EVENTS_DISABLE") _S(32, "PR_TASK_PERF_EVENTS_ENABLE") _S(33, "PR_MCE_KILL") _S(34, "PR_MCE_KILL_GET") _S(35, "PR_SET_MM") _S(36, "PR_SET_CHILD_SUBREAPER") _S(37, "PR_GET_CHILD_SUBREAPER") _S(38, "PR_SET_NO_NEW_PRIVS") _S(39, "PR_GET_NO_NEW_PRIVS") _S(40, "PR_GET_TID_ADDRESS") _S(41, "PR_SET_THP_DISABLE") _S(42, "PR_GET_THP_DISABLE") _S(43, "PR_MPX_ENABLE_MANAGEMENT") _S(44, "PR_MPX_DISABLE_MANAGEMENT") _S(45, "PR_SET_FP_MODE") _S(46, "PR_GET_FP_MODE") _S(47, "PR_CAP_AMBIENT") _S(50, "PR_SVE_SET_VL") _S(51, "PR_SVE_GET_VL") _S(52, "PR_GET_SPECULATION_CTRL") _S(53, "PR_SET_SPECULATION_CTRL") _S(54, "PR_PAC_RESET_KEYS") _S(55, "PR_SET_TAGGED_ADDR_CTRL") _S(56, "PR_GET_TAGGED_ADDR_CTRL") _S(57, "PR_SET_IO_FLUSHER") _S(58, "PR_GET_IO_FLUSHER") _S(59, "PR_SET_SYSCALL_USER_DISPATCH") _S(60, "PR_PAC_SET_ENABLED_KEYS") _S(61, "PR_PAC_GET_ENABLED_KEYS") _S(62, "PR_SCHED_CORE") _S(63, "PR_SME_SET_VL") _S(64, "PR_SME_GET_VL") _S(65, "PR_SET_MDWE") _S(66, "PR_GET_MDWE") _S(67, "PR_SET_MEMORY_MERGE") _S(68, "PR_GET_MEMORY_MERGE") _S(69, "PR_RISCV_V_SET_CONTROL") _S(70, "PR_RISCV_V_GET_CONTROL") audit-userspace-4.0.5/auparse/private.h000066400000000000000000000026121501761310600201020ustar00rootroot00000000000000/* private.h -- * Copyright 2007,2013,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef _PRIVATE_H_ #define _PRIVATE_H_ #include "auparse.h" #include "libaudit.h" #include "dso.h" AUDIT_HIDDEN_START /* Internal syslog messaging */ #define audit_msg auparse_msg #define set_aumessage_mode set_aup_message_mode void auparse_msg(const auparse_state_t *au, int priority, const char *fmt, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 3, 4))); #else ; #endif void set_aup_message_mode(auparse_state_t *au, message_t mode, debug_message_t debug); AUDIT_HIDDEN_END #endif audit-userspace-4.0.5/auparse/prottab.h000066400000000000000000000020611501761310600201010ustar00rootroot00000000000000/* prottab.h -- * Copyright 2012-13 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/mman-common.h */ _S(1, "PROT_READ" ) _S(2, "PROT_WRITE" ) _S(4, "PROT_EXEC" ) _S(8, "PROT_SEM" ) _S(0x01000000, "PROT_GROWSDOWN") _S(0x02000000, "PROT_GROWSUP") audit-userspace-4.0.5/auparse/ptracetab.h000066400000000000000000000044771501761310600204100ustar00rootroot00000000000000/* ptracetab.h -- * Copyright 2012-14,16,18,20-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/ptrace.h * ./arch/x86/include/uapi/asm/ptrace-abi.h (0 - 30) */ _S(0, "PTRACE_TRACEME" ) _S(1, "PTRACE_PEEKTEXT" ) _S(2, "PTRACE_PEEKDATA" ) _S(3, "PTRACE_PEEKUSER" ) _S(4, "PTRACE_POKETEXT" ) _S(5, "PTRACE_POKEDATA" ) _S(6, "PTRACE_POKEUSER" ) _S(7, "PTRACE_CONT" ) _S(8, "PTRACE_KILL" ) _S(9, "PTRACE_SINGLESTEP" ) _S(12, "PTRACE_GETREGS" ) _S(13, "PTRACE_SETREGS" ) _S(14, "PTRACE_GETFPREGS" ) _S(15, "PTRACE_SETFPREGS" ) _S(16, "PTRACE_ATTACH" ) _S(17, "PTRACE_DETACH" ) _S(18, "PTRACE_GETFPXREGS" ) _S(19, "PTRACE_SETFPXREGS" ) _S(24, "PTRACE_SYSCALL" ) _S(25, "PTRACE_GET_THREAD_AREA") _S(26, "PTRACE_SET_THREAD_AREA") _S(30, "PTRACE_ARCH_PRCTL" ) _S(31, "PTRACE_SYSEMU" ) _S(32, "PTRACE_SYSEMU_SINGLESTEP") _S(33, "PTRACE_SINGLEBLOCK" ) _S(0x4200, "PTRACE_SETOPTIONS" ) _S(0x4201, "PTRACE_GETEVENTMSG" ) _S(0x4202, "PTRACE_GETSIGINFO" ) _S(0x4203, "PTRACE_SETSIGINFO" ) _S(0x4204, "PTRACE_GETREGSET" ) _S(0x4205, "PTRACE_SETREGSET" ) _S(0x4206, "PTRACE_SEIZE" ) _S(0x4207, "PTRACE_INTERRUPT" ) _S(0x4208, "PTRACE_LISTEN" ) _S(0x4209, "PTRACE_PEEKSIGINFO" ) _S(0x420a, "PTRACE_GETSIGMASK" ) _S(0x420b, "PTRACE_SETSIGMASK" ) _S(0x420c, "PTRACE_SECCOMP_GET_FILTER" ) _S(0x420d, "PTRACE_SECCOMP_GET_METADATA" ) _S(0x420e, "PTRACE_GET_SYSCALL_INFO" ) _S(0x420f, "PTRACE_GET_RSEQ_CONFIGURATION" ) _S(0x4210, "PTRACE_SET_SYSCALL_USER_DISPATCH_CONFIG" ) _S(0x4211, "PTRACE_GET_SYSCALL_USER_DISPATCH_CONFIG" ) audit-userspace-4.0.5/auparse/recvtab.h000066400000000000000000000031361501761310600200600ustar00rootroot00000000000000/* recvtab.h -- * Copyright 2012-14 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/linux/socket.h */ _S(0x00000001, "MSG_OOB") _S(0x00000002, "MSG_PEEK") _S(0x00000004, "MSG_DONTROUTE") _S(0x00000008, "MSG_CTRUNC") _S(0x00000010, "MSG_PROXY") _S(0x00000020, "MSG_TRUNC") _S(0x00000040, "MSG_DONTWAIT") _S(0x00000080, "MSG_EOR") _S(0x00000100, "MSG_WAITALL") _S(0x00000200, "MSG_FIN") _S(0x00000400, "MSG_SYN") _S(0x00000800, "MSG_CONFIRM") _S(0x00001000, "MSG_RST") _S(0x00002000, "MSG_ERRQUEUE") _S(0x00004000, "MSG_NOSIGNAL") _S(0x00008000, "MSG_MORE") _S(0x00010000, "MSG_WAITFORONE") _S(0x00020000, "MSG_SENDPAGE_NOTLAST") _S(0x00040000, "MSG_BATCH") _S(0x20000000, "MSG_FASTOPEN") _S(0x40000000, "MSG_CMSG_CLOEXEC") _S(0x80000000, "MSG_CMSG_COMPAT") audit-userspace-4.0.5/auparse/rlimittab.h000066400000000000000000000024201501761310600204140ustar00rootroot00000000000000/* rlimittab.h -- * Copyright 2012-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/resource.h */ _S(0, "RLIMIT_CPU") _S(1, "RLIMIT_FSIZE") _S(2, "RLIMIT_DATA") _S(3, "RLIMIT_STACK") _S(4, "RLIMIT_CORE") _S(5, "RLIMIT_RSS") _S(6, "RLIMIT_NPROC") _S(7, "RLIMIT_NOFILE") _S(8, "RLIMIT_MEMLOCK") _S(9, "RLIMIT_AS") _S(10,"RLIMIT_LOCKS") _S(11,"RLIMIT_SIGPENDING") _S(12,"RLIMIT_MSGQUEUE") _S(13,"RLIMIT_NICE") _S(14,"RLIMIT_RTPRIO") _S(15,"RLIMIT_RTTIME") audit-userspace-4.0.5/auparse/rnode.h000066400000000000000000000047501501761310600175440ustar00rootroot00000000000000/* rnode.h -- * Copyright 2007,2016-17,21 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef RNODE_HEADER #define RNODE_HEADER #define NFIELDS 36 /* This is the data node of the fields list. Any data elements that are * per field goes here. */ typedef struct _nvnode{ char *name; // The name string char *val; // The value field char *interp_val; // The value field interpreted unsigned int item; // Which item of the same event } nvnode; /* This is the field list head. */ typedef struct { nvnode *array; // array of fields unsigned int cur; // Index to current node unsigned int cnt; // How many items in this list unsigned int size; // Number of allocated items char *record; // Holds the parsed up record char *end; // End of the parsed up record } nvlist; /* This is the node of the linked list. Only data elements that are per * record goes here. */ typedef struct _rnode{ char *record; // The whole unparsed record char *interp; // The interpretations that go with record const char *cwd; // This is pass thru for ellist int type; // record type (KERNEL, USER, LOGIN, etc) int machine; // The machine type for the event int syscall; // The syscall for the event unsigned long long a0; // arg 0 to the syscall unsigned long long a1; // arg 1 to the syscall nvlist nv; // name-value linked list of parsed elements unsigned int item; // Which item of the same event int list_idx; // The index into the source list, points to where record was found unsigned int line_number; // The line number where record was found struct _rnode* next; // Next record node pointer } rnode; #endif audit-userspace-4.0.5/auparse/schedtab.h000066400000000000000000000020251501761310600202030ustar00rootroot00000000000000/* schedtab.h -- * Copyright 2013-14 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/sched.h */ _S(0, "SCHED_OTHER" ) _S(1, "SCHED_FIFO" ) _S(2, "SCHED_RR" ) _S(3, "SCHED_BATCH" ) _S(5, "SCHED_IDLE" ) _S(6, "SCHED_DEADLINE") audit-userspace-4.0.5/auparse/seccomptab.h000066400000000000000000000021761501761310600205550ustar00rootroot00000000000000/* seccomptab.h -- * Copyright 2012-13,2018,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/seccomp.h */ _S(0x80000000U, "kill-process") _S(0x00000000U, "kill-thread") _S(0x00030000U, "trap" ) _S(0x00050000U, "errno" ) _S(0x7fc00000U, "user-notify") _S(0x7ff00000U, "trace" ) _S(0x7ffc0000U, "log" ) _S(0x7fff0000U, "allow" ) audit-userspace-4.0.5/auparse/seektab.h000066400000000000000000000017501501761310600200500ustar00rootroot00000000000000/* seektab.h -- * Copyright 2013 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/fs.h */ _S(0, "SEEK_SET") _S(1, "SEEK_CUR") _S(2, "SEEK_END") _S(3, "SEEK_DATA") _S(4, "SEEK_HOLE") audit-userspace-4.0.5/auparse/shm_modetab.h000066400000000000000000000020431501761310600207100ustar00rootroot00000000000000/* shm_mode.h -- * Copyright 2013 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/linux/shm.h * include/uapi/linux/shm.h */ _S(00001000, "SHM_DEST" ) _S(00002000, "SHM_LOCKED" ) _S(00004000, "SHM_HUGETLB" ) _S(00010000, "SHM_NORESERVE" ) audit-userspace-4.0.5/auparse/signaltab.h000066400000000000000000000027531501761310600204020ustar00rootroot00000000000000/* signaltab.h -- * Copyright 2012-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/asm-generic/signal.h */ _S(0, "SIG0" ) _S(1, "SIGHUP" ) _S(2, "SIGINT" ) _S(3, "SIGQUIT" ) _S(4, "SIGILL" ) _S(5, "SIGTRAP" ) _S(6, "SIGABRT" ) _S(7, "SIGBUS" ) _S(8, "SIGFPE" ) _S(9, "SIGKILL" ) _S(10, "SIGUSR1" ) _S(11, "SIGSEGV" ) _S(12, "SIGUSR2" ) _S(13, "SIGPIPE" ) _S(14, "SIGALRM" ) _S(15, "SIGTERM" ) _S(16, "SIGSTKFLT" ) _S(17, "SIGCHLD" ) _S(18, "SIGCONT" ) _S(19, "SIGSTOP" ) _S(20, "SIGTSTP" ) _S(21, "SIGTTIN" ) _S(22, "SIGTTOU" ) _S(23, "SIGURG" ) _S(24, "SIGXCPU" ) _S(25, "SIGXFSZ" ) _S(26, "SIGVTALRM" ) _S(27, "SIGPROF" ) _S(28, "SIGWINCH" ) _S(29, "SIGIO" ) _S(30, "IGPWR" ) _S(31, "SIGSYS" ) audit-userspace-4.0.5/auparse/sockleveltab.h000066400000000000000000000032611501761310600211070ustar00rootroot00000000000000/* sockleveltab.h -- * Copyright 2013-15,2018 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Authors: * Steve Grubb * Location: include/linux/socket.h */ _S(0, "SOL_IP") _S(6, "SOL_TCP") _S(17, "SOL_UDP") _S(41, "SOL_IPV6") _S(58, "SOL_ICMPV6") _S(132, "SOL_SCTP") _S(136, "SOL_UDPLITE") _S(255, "SOL_RAW") _S(256, "SOL_IPX") _S(257, "SOL_AX25") _S(258, "SOL_ATALK") _S(259, "SOL_NETROM") _S(260, "SOL_ROSE") _S(261, "SOL_DECNET") _S(263, "SOL_PACKET") _S(264, "SOL_ATM") _S(265, "SOL_AAL") _S(266, "SOL_IRDA") _S(267, "SOL_NETBEUI") _S(268, "SOL_LLC") _S(269, "SOL_DCCP") _S(270, "SOL_NETLINK") _S(271, "SOL_TIPC") _S(272, "SOL_RXRPC") _S(273, "SOL_PPPOL2TP") _S(274, "SOL_BLUETOOTH") _S(275, "SOL_PNPIPE") _S(276, "SOL_RDS") _S(277, "SOL_IUCV") _S(278, "SOL_CAIF") _S(279, "SOL_ALG") _S(280, "SOL_NFC") _S(281, "SOL_KCM") _S(282, "SOL_TLS") _S(283, "SOL_XDP") _S(284, "SOL_MPTCP") _S(285, "SOL_MCTP") _S(286, "SOL_SMC") _S(287, "SOL_VSOCK") audit-userspace-4.0.5/auparse/sockoptnametab.h000066400000000000000000000057031501761310600214460ustar00rootroot00000000000000/* sockoptnametab.h -- * Copyright 2013-16,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * File: include/uapi/asm-generic/socket.h */ _S(1, "SO_DEBUG") _S(2, "SO_REUSEADDR") _S(3, "SO_TYPE") _S(4, "SO_ERROR") _S(5, "SO_DONTROUTE") _S(6, "SO_BROADCAST") _S(7, "SO_SNDBUF") _S(8, "SO_RCVBUF") _S(9, "SO_KEEPALIVE") _S(10, "SO_OOBINLINE") _S(11, "SO_NO_CHECK") _S(12, "SO_PRIORITY") _S(13, "SO_LINGER") _S(14, "SO_BSDCOMPAT") _S(15, "SO_REUSEPORT") _S(16, "SO_PASSCRED") _S(17, "SO_PEERCRED") _S(18, "SO_RCVLOWAT") _S(19, "SO_SNDLOWAT") _S(20, "SO_RCVTIMEO") _S(21, "SO_SNDTIMEO") _S(22, "SO_SECURITY_AUTHENTICATION") _S(23, "SO_SECURITY_ENCRYPTION_TRANSPORT") _S(24, "SO_SECURITY_ENCRYPTION_NETWORK") _S(25, "SO_BINDTODEVICE") _S(26, "SO_ATTACH_FILTER") _S(27, "SO_DETACH_FILTER") _S(28, "SO_PEERNAME") _S(29, "SO_TIMESTAMP") _S(30, "SO_ACCEPTCONN") _S(31, "SO_PEERSEC") _S(32, "SO_SNDBUFFORCE") _S(33, "SO_RCVBUFFORCE") _S(34, "SO_PASSSEC") _S(35, "SO_TIMESTAMPNS") _S(36, "SO_MARK") _S(37, "SO_TIMESTAMPING") _S(38, "SO_PROTOCOL") _S(39, "SO_DOMAIN") _S(40, "SO_RXQ_OVFL") _S(41, "SO_WIFI_STATUS") _S(42, "SO_PEEK_OFF") _S(43, "SO_NOFCS") _S(44, "SO_LOCK_FILTER") _S(45, "SO_SELECT_ERR_QUEUE") _S(46, "SO_BUSY_POLL") _S(47, "SO_MAX_PACING_RATE") _S(48, "SO_BPF_EXTENSIONS") _S(49, "SO_INCOMING_CPU") _S(50, "SO_ATTACH_BPF") _S(51, "SO_ATTACH_REUSEPORT_CBPF") _S(52, "SO_ATTACH_REUSEPORT_EBPF") _S(53, "SO_CNX_ADVICE") _S(54, "SCM_TIMESTAMPING_OPT_STATS") _S(55, "SO_MEMINFO") _S(56, "SO_INCOMING_NAPI_ID") _S(57, "SO_COOKIE") _S(58, "SCM_TIMESTAMPING_PKTINFO") _S(59, "SO_PEERGROUPS") _S(60, "SO_ZEROCOPY") _S(61, "SO_TXTIME") _S(62, "SO_BINDTOIFINDEX") _S(63, "SO_TIMESTAMP_NEW") _S(64, "SO_TIMESTAMPNS_NEW") _S(65, "SO_TIMESTAMPING_NEW") _S(66, "SO_RCVTIMEO_NEW") _S(67, "SO_SNDTIMEO_NEW") _S(68, "SO_DETACH_REUSEPORT_BPF") _S(69, "SO_PREFER_BUSY_POLL") _S(70, "SO_BUSY_POLL_BUDGET") _S(71, "SO_NETNS_COOKIE") _S(72, "SO_BUF_LOCK") _S(73, "SO_RESERVE_MEM") _S(74, "SO_TXREHASH") _S(75, "SO_RCVMARK") _S(76, "SO_PASSPIDFD") _S(77, "SO_PEERPIDFD") // PPC has these different _S(116, "SO_RCVLOWAT") _S(117, "SO_SNDLOWAT") _S(118, "SO_RCVTIMEO") _S(119, "SO_SNDTIMEO") _S(120, "SO_PASSCRED") _S(121, "SO_PEERCRED") audit-userspace-4.0.5/auparse/socktab.h000066400000000000000000000027231501761310600200610ustar00rootroot00000000000000/* socktab.h -- * Copyright 2007,2011-13 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/uapi/linux/net.h */ _S(SYS_SOCKET, "socket" ) _S(SYS_BIND, "bind" ) _S(SYS_CONNECT, "connect" ) _S(SYS_LISTEN, "listen" ) _S(SYS_ACCEPT, "accept" ) _S(SYS_GETSOCKNAME, "getsockname" ) _S(SYS_GETPEERNAME, "getpeername" ) _S(SYS_SOCKETPAIR, "socketpair" ) _S(SYS_SEND, "send" ) _S(SYS_RECV, "recv" ) _S(SYS_SENDTO, "sendto" ) _S(SYS_RECVFROM, "recvfrom" ) _S(SYS_SHUTDOWN, "shutdown" ) _S(SYS_SETSOCKOPT, "setsockopt" ) _S(SYS_GETSOCKOPT, "getsockopt" ) _S(SYS_SENDMSG, "sendmsg" ) _S(SYS_RECVMSG, "recvmsg" ) _S(SYS_ACCEPT4, "accept4" ) _S(19, "recvmmsg" ) _S(20, "sendmmsg" ) audit-userspace-4.0.5/auparse/socktypetab.h000066400000000000000000000020321501761310600207540ustar00rootroot00000000000000/* socktypetab.h -- * Copyright 2012 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/linux/net.h */ _S(1, "SOCK_STREAM") _S(2, "SOCK_DGRAM") _S(3, "SOCK_RAW") _S(4, "SOCK_RDM") _S(5, "SOCK_SEQPACKET") _S(6, "SOCK_DCCP") _S(10, "SOCK_PACKET") audit-userspace-4.0.5/auparse/tcpoptnametab.h000066400000000000000000000036441501761310600212770ustar00rootroot00000000000000/* tcpoptnametab.h -- * Copyright 2013-14,2018 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Authors: * Steve Grubb * Location: include/uapi/linux/tcp.h */ _S(1, "TCP_NODELAY") _S(2, "TCP_MAXSEG") _S(3, "TCP_CORK") _S(4, "TCP_KEEPIDLE") _S(5, "TCP_KEEPINTVL") _S(6, "TCP_KEEPCNT") _S(7, "TCP_SYNCNT") _S(8, "TCP_LINGER2") _S(9, "TCP_DEFER_ACCEPT") _S(10, "TCP_WINDOW_CLAMP") _S(11, "TCP_INFO") _S(12, "TCP_QUICKACK") _S(13, "TCP_CONGESTION") _S(14, "TCP_MD5SIG") _S(15, "TCP_COOKIE_TRANSACTIONS") _S(16, "TCP_THIN_LINEAR_TIMEOUTS") _S(17, "TCP_THIN_DUPACK") _S(18, "TCP_USER_TIMEOUT") _S(19, "TCP_REPAIR") _S(20, "TCP_REPAIR_QUEUE") _S(21, "TCP_QUEUE_SEQ") _S(22, "TCP_REPAIR_OPTIONS") _S(23, "TCP_FASTOPEN") _S(24, "TCP_TIMESTAMP") _S(25, "TCP_NOTSENT_LOWAT") _S(26, "TCP_CC_INFO") _S(27, "TCP_SAVE_SYN") _S(28, "TCP_SAVED_SYN") _S(29, "TCP_REPAIR_WINDOW") _S(30, "TCP_FASTOPEN_CONNECT") _S(31, "TCP_ULP") _S(32, "TCP_MD5SIG_EXT") _S(33, "TCP_FASTOPEN_KEY") _S(34, "TCP_FASTOPEN_NO_COOKIE") _S(35, "TCP_ZEROCOPY_RECEIVE") _S(36, "TCP_INQ") _S(37, "TCP_TX_DELAY") _S(38, "TCP_AO_ADD_KEY") _S(39, "TCP_AO_DEL_KEY") _S(40, "TCP_AO_INFO") _S(41, "TCP_AO_GET_KEYS") _S(42, "TCP_AO_REPAIR") audit-userspace-4.0.5/auparse/test/000077500000000000000000000000001501761310600172355ustar00rootroot00000000000000audit-userspace-4.0.5/auparse/test/Makefile.am000066400000000000000000000112331501761310600212710ustar00rootroot00000000000000# Makefile.am -- # Copyright 2006-08,2014-17 Red Hat Inc. # All Rights Reserved. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig *.cur check_PROGRAMS = auparse_test auparselol_test lookup_test dist_check_SCRIPTS = auparse_test.py EXTRA_DIST = auparse_test.ref auparse_test.ref.py test.log test2.log test3.log test4.log auditd_raw.sed AM_CPPFLAGS = -I${top_srcdir}/auparse -I${top_srcdir}/lib lookup_test_SOURCES = lookup_test.c lookup_test_LDFLAGS = -static lookup_test_LDADD = ${top_builddir}/auparse/libauparse.la \ ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la lookup_test_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la auparse_test_SOURCES = auparse_test.c auparse_test_LDFLAGS = -static auparse_test_LDADD = ${top_builddir}/auparse/libauparse.la \ ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la auparse_test_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la auparselol_test_SOURCES = auparselol_test.c auparselol_test_LDFLAGS = -static auparselol_test_LDADD = ${top_builddir}/auparse/libauparse.la \ ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la auparselol_test_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la ${top_builddir}/common/libaucommon.la drop_srcdir = sed 's,$(srcdir)/test,test,' check-local: auparse_test auparselol_test lookup_test test "$(top_srcdir)" = "$(top_builddir)" || \ cp $(top_srcdir)/auparse/test/test*.log . LC_ALL=C \ ./auparse_test > auparse_test.cur diff -u $(top_srcdir)/auparse/test/auparse_test.ref auparse_test.cur ./auparselol_test -f test3.log --check | sort > auparse_test.cur sed -f $(top_srcdir)/auparse/test/auditd_raw.sed test3.log | sort > auparse_test.raw diff -u auparse_test.raw auparse_test.cur if USE_PYTHON3 cp ${top_builddir}/bindings/swig/python3/.libs/_audit.so ${top_builddir}/bindings/swig/python3 PYTHONPATH=${top_builddir}/bindings/python/python3/.libs/ \ PYTHONDONTWRITEBYTECODE=1 \ LD_LIBRARY_PATH=${top_builddir}/auparse/.libs \ srcdir=$(srcdir) $(srcdir)/auparse_test.py \ | $(drop_srcdir) > auparse_test.cur diff -u $(top_srcdir)/auparse/test/auparse_test.ref.py auparse_test.cur endif ./lookup_test echo -e "===================\nAuparse Test Passes\n===================" diffcheck: auparse_test auparselol_test ./auparse_test > auparse_test.cur diff -u $(srcdir)/auparse_test.ref auparse_test.cur ./auparselol_test -f test3.log --check | sort > auparse_test.cur sed -f ./auditd_raw.sed test3.log | sort > auparse_test.raw diff -u auparse_test.raw auparse_test.cur memcheck: auparse_test valgrind --leak-check=yes --show-reachable=yes ./auparse_test pycheck: auparse_test.py if USE_PYTHON3 PYTHONPATH=${top_builddir}/bindings/python/python3/.libs/ \ PYTHONDONTWRITEBYTECODE=1 \ LD_LIBRARY_PATH=${top_builddir}/auparse/.libs \ srcdir=$(srcdir) $(srcdir)/auparse_test.py endif pydiffcheck: auparse_test.py if USE_PYTHON3 PYTHONPATH=${top_builddir}/bindings/python/python3/.libs/ \ PYTHONDONTWRITEBYTECODE=1 \ LD_LIBRARY_PATH=${top_builddir}/auparse/.libs \ srcdir=$(srcdir) $(srcdir)/auparse_test.py \ | $(drop_srcdir) > auparse_test.cur diff -u $(srcdir)/auparse_test.ref.py auparse_test.cur endif pymemcheck: auparse_test.py if USE_PYTHON3 PYTHONPATH=${top_builddir}/bindings/python/python3/.libs/ \ PYTHONDONTWRITEBYTECODE=1 \ LD_LIBRARY_PATH=${top_builddir}/auparse/.libs srcdir=$(srcdir) valgrind --leak-check=yes --show-reachable=yes python $(srcdir)/auparse_test.py ${top_builddir}/bindings/python/build/*/auparse.so: ${top_srcdir}/bindings/python/auparse_python.c cd ${top_builddir}/bindings/python && make endif clean-generic: $(RM) *.cur $(RM) auparse_test.raw if USE_PYTHON3 $(RM) ${top_builddir}/bindings/swig/python3/_audit.so endif test "$(top_srcdir)" = "$(top_builddir)" || $(RM) test*.log audit-userspace-4.0.5/auparse/test/auditd_raw.sed000066400000000000000000000015721501761310600220620ustar00rootroot00000000000000s/ cwd/ cwd/ s/ comm=/ comm=/ s/msg='// s/(hostname=/hostname=/ s/success)/success/ s/ : exe=/ exe=/ s/'$// s/): a/): a/ s/, addr=/ addr=/ s/, terminal=/ terminal=/ s/tty pid=/pid=/ s/Unknown permission start for class system // s/Unknown permission stop for class system // s/ exe=/ exe=/ s/ pam: default-context/ default-context/ s/ avc: denied { stop } for auid=/ auid=/ s/old ses=/ses=/ s/new ses=/ses=/ s/old auid=/auid=/ s/login pid=/pid=/ s/user pid=/pid=/ s/new auid=/auid=/ s/auditd start, ver=/ver=/ s/policy loaded auid=/auid=/ s/auditd normal halt, sending auid=/auid=/ s/op=change password id=/op=change id=/ s/avc: received policyload notice (seqno=\(\d+)\))/seqno=\1/ s/PAM: accounting acct/acct/ s/PAM: session open acct/acct/ s/PAM: session close acct/acct/ s/PAM: setcred acct/acct/ s/avc: denied { read write } for pid=/seresult=denied seperms=read,write pid=/ audit-userspace-4.0.5/auparse/test/auparse_test.c000066400000000000000000000326601501761310600221070ustar00rootroot00000000000000#include #include #include #include #include #include #include "libaudit.h" #include "auparse.h" // NOTE: First two run together on purpose, #3 is buf[1] static const char *buf[] = { "type=LOGIN msg=audit(1143146623.787:142): login pid=2027 uid=0 old auid=4294967295 new auid=848\n" "type=SYSCALL msg=audit(1143146623.875:143): arch=c000003e syscall=188 success=yes exit=0 a0=7fffffa9a9f0 a1=3958d11333 a2=5131f0 a3=20 items=1 pid=2027 auid=848 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=tty3 comm=\"login\" exe=\"/bin/login\" subj=system_u:system_r:local_login_t:s0-s0:c0.c255\n", "type=USER_LOGIN msg=audit(1143146623.879:146): user pid=2027 uid=0 auid=848 msg=\'uid=848: exe=\"/bin/login\" (hostname=?, addr=?, terminal=tty3 res=success)\'\n", NULL }; unsigned int walked_fields = 0; #define FIELDS_EXPECTED 403 static void walk_test(auparse_state_t *au) { int event_cnt = 1, record_cnt; do { if (auparse_first_record(au) <= 0) { printf("Error getting first record (%s)\n", strerror(errno)); exit(1); } printf("event %d has %u records\n", event_cnt, auparse_get_num_records(au)); record_cnt = 1; do { printf(" record %d of type %d(%s) has %u fields\n", record_cnt, auparse_get_type(au), audit_msg_type_to_name(auparse_get_type(au)), auparse_get_num_fields(au)); printf(" line=%u file=%s\n", auparse_get_line_number(au), auparse_get_filename(au) ? auparse_get_filename(au) : "None"); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) { printf("Error getting timestamp - aborting\n"); exit(1); } printf(" event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec, e->milli, e->serial, e->host ? e->host : "?"); auparse_first_field(au); do { printf(" %s=%s (%s)\n", auparse_get_field_name(au), auparse_get_field_str(au), auparse_interpret_field(au)); walked_fields++; } while (auparse_next_field(au) > 0); printf("\n"); record_cnt++; } while(auparse_next_record(au) > 0); event_cnt++; } while (auparse_next_event(au) > 0); } void light_test(auparse_state_t *au) { int record_cnt; do { if (auparse_first_record(au) <= 0) { puts("Error getting first record"); exit(1); } printf("event has %u records\n", auparse_get_num_records(au)); record_cnt = 1; do { printf(" record %d of type %d(%s) has %u fields\n", record_cnt, auparse_get_type(au), audit_msg_type_to_name(auparse_get_type(au)), auparse_get_num_fields(au)); printf(" line=%u file=%s\n", auparse_get_line_number(au), auparse_get_filename(au) ? auparse_get_filename(au) : "None"); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) { printf("Error getting timestamp - aborting\n"); exit(1); } printf(" event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec, e->milli, e->serial, e->host ? e->host : "?"); printf("\n"); record_cnt++; } while(auparse_next_record(au) > 0); } while (auparse_next_event(au) > 0); } void simple_search(ausource_t source, austop_t where) { auparse_state_t *au; const char *val; if (source == AUSOURCE_FILE) { au = auparse_init(AUSOURCE_FILE, "./test.log"); val = "4294967295"; } else { au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); val = "848"; } if (au == NULL) { printf("auparse_init error - %s\n", strerror(errno)); exit(1); } if (ausearch_add_item(au, "auid", "=", val, AUSEARCH_RULE_CLEAR)){ printf("ausearch_add_item error - %s\n", strerror(errno)); exit(1); } if (ausearch_set_stop(au, where)){ printf("ausearch_set_stop error - %s\n", strerror(errno)); exit(1); } if (ausearch_next_event(au) <= 0) printf("Error searching for auid - %s\n", strerror(errno)); else printf("Found %s = %s\n", auparse_get_field_name(au), auparse_get_field_str(au)); auparse_destroy(au); } void compound_search(ausearch_rule_t how) { auparse_state_t *au; au = auparse_init(AUSOURCE_FILE, "./test.log"); if (au == NULL) { printf("auparse_init error - %s\n", strerror(errno)); exit(1); } if (how == AUSEARCH_RULE_AND) { if (ausearch_add_item(au, "uid", "=", "0", AUSEARCH_RULE_CLEAR)){ printf("ausearch_add_item 1 error - %s\n", strerror(errno)); exit(1); } if (ausearch_add_item(au, "pid", "=", "13015", how)){ printf("ausearch_add_item 2 error - %s\n", strerror(errno)); exit(1); } if (ausearch_add_item(au, "type", "=", "USER_START", how)){ printf("ausearch_add_item 3 error - %s\n", strerror(errno)); exit(1); } } else { if (ausearch_add_item(au, "auid", "=", "42", AUSEARCH_RULE_CLEAR)){ printf("ausearch_add_item 4 error - %s\n", strerror(errno)); exit(1); } // should stop on this one if (ausearch_add_item(au, "auid", "=", "0", how)){ printf("ausearch_add_item 5 error - %s\n", strerror(errno)); exit(1); } if (ausearch_add_item(au, "auid", "=", "500", how)){ printf("ausearch_add_item 6 error - %s\n", strerror(errno)); exit(1); } } if (ausearch_set_stop(au, AUSEARCH_STOP_FIELD)){ printf("ausearch_set_stop error - %s\n", strerror(errno)); exit(1); } if (ausearch_next_event(au) <= 0) printf("Error searching for auid - %s\n", strerror(errno)); else printf("Found %s = %s\n", auparse_get_field_name(au), auparse_get_field_str(au)); auparse_destroy(au); } void regex_search(const char *expr) { auparse_state_t *au; int rc; au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); if (au == NULL) { printf("auparse_init error - %s\n", strerror(errno)); exit(1); } if (ausearch_add_regex(au, expr)){ printf("ausearch_add_regex error - %s\n", strerror(errno)); exit(1); } if (ausearch_set_stop(au, AUSEARCH_STOP_RECORD)){ printf("ausearch_set_stop error - %s\n", strerror(errno)); exit(1); } rc = ausearch_next_event(au); if (rc < 0) printf("Error searching for %s - %s\n", expr, strerror(errno)); else if (rc == 0) printf("Not found\n"); else printf("Found %s = %s\n", auparse_get_field_name(au), auparse_get_field_str(au)); auparse_destroy(au); } static void auparse_callback(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { int *event_cnt = (int *)user_data; int record_cnt; if (cb_event_type == AUPARSE_CB_EVENT_READY) { if (auparse_first_record(au) <= 0) { printf("can't get first record\n"); return; } printf("event %d has %u records\n", *event_cnt, auparse_get_num_records(au)); record_cnt = 1; do { printf(" record %d of type %d(%s) has %u fields\n", record_cnt, auparse_get_type(au), audit_msg_type_to_name(auparse_get_type(au)), auparse_get_num_fields(au)); printf(" line=%u file=%s\n", auparse_get_line_number(au), auparse_get_filename(au) ? auparse_get_filename(au) : "None"); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) { return; } printf(" event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec, e->milli, e->serial, e->host ? e->host : "?"); auparse_first_field(au); do { printf(" %s=%s (%s)\n", auparse_get_field_name(au), auparse_get_field_str(au), auparse_interpret_field(au)); } while (auparse_next_field(au) > 0); printf("\n"); record_cnt++; } while(auparse_next_record(au) > 0); (*event_cnt)++; } } int main(void) { //char *files[4] = { "test.log", "test2.log", "test3.log", NULL }; char *files[3] = { "test2.log", "test.log", NULL }; setlocale (LC_ALL, ""); auparse_state_t *au; au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } printf("Starting Test 1, iterate...\n"); while (auparse_next_event(au) > 0) { if (auparse_find_field(au, "auid")) { printf("%s=%s\n", auparse_get_field_name(au), auparse_get_field_str(au)); printf("interp auid=%s\n", auparse_interpret_field(au)); } else printf("Error iterating to auid\n"); } auparse_reset(au); while (auparse_next_event(au) > 0) { if (auparse_find_field(au, "auid")) { do { printf("%s=%s\n", auparse_get_field_name(au), auparse_get_field_str(au)); printf("interp auid=%s\n", auparse_interpret_field(au)); } while (auparse_find_field_next(au)); } else printf("Error iterating to auid\n"); } printf("Test 1 Done\n\n"); /* Reset, now lets go to beginning and walk the list manually */ printf("Starting Test 2, walk events, records, and fields...\n"); auparse_reset(au); walk_test(au); auparse_destroy(au); printf("Test 2 Done\n\n"); /* Reset, now lets go to beginning and walk the list manually */ printf("Starting Test 3, walk events, records of 1 buffer...\n"); au = auparse_init(AUSOURCE_BUFFER, buf[1]); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } light_test(au); auparse_destroy(au); printf("Test 3 Done\n\n"); printf("Starting Test 4, walk events, records of 1 file...\n"); au = auparse_init(AUSOURCE_FILE, "./test.log"); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } walk_test(au); auparse_destroy(au); printf("Test 4 Done\n\n"); printf("Starting Test 5, walk events, records of 2 files...\n"); au = auparse_init(AUSOURCE_FILE_ARRAY, files); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } walk_test(au); auparse_destroy(au); printf("Test 5 Done\n\n"); printf("Starting Test 6, search...\n"); au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } if (ausearch_add_item(au, "auid", "=", "500", AUSEARCH_RULE_CLEAR)){ printf("Error - %s", strerror(errno)); return 1; } if (ausearch_set_stop(au, AUSEARCH_STOP_EVENT)){ printf("Error - %s", strerror(errno)); exit(1); } if (ausearch_next_event(au) != 0) { printf("Error search found something it shouldn't have\n"); } puts("auid = 500 not found...which is correct"); ausearch_clear(au); auparse_destroy(au); au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); if (ausearch_add_item(au,"auid", "exists", NULL, AUSEARCH_RULE_CLEAR)){ printf("Error - %s", strerror(errno)); return 1; } if (ausearch_set_stop(au, AUSEARCH_STOP_EVENT)){ printf("Error - %s", strerror(errno)); exit(1); } if (ausearch_next_event(au) <= 0) { printf("Error searching for existence of auid\n"); } puts("auid exists...which is correct"); puts("Testing BUFFER_ARRAY, stop on field"); simple_search(AUSOURCE_BUFFER_ARRAY, AUSEARCH_STOP_FIELD); puts("Testing BUFFER_ARRAY, stop on record"); simple_search(AUSOURCE_BUFFER_ARRAY, AUSEARCH_STOP_RECORD); puts("Testing BUFFER_ARRAY, stop on event"); simple_search(AUSOURCE_BUFFER_ARRAY, AUSEARCH_STOP_EVENT); puts("Testing test.log, stop on field"); simple_search(AUSOURCE_FILE, AUSEARCH_STOP_FIELD); puts("Testing test.log, stop on record"); simple_search(AUSOURCE_FILE, AUSEARCH_STOP_RECORD); puts("Testing test.log, stop on event"); simple_search(AUSOURCE_FILE, AUSEARCH_STOP_EVENT); auparse_destroy(au); printf("Test 6 Done\n\n"); printf("Starting Test 7, compound search...\n"); au = auparse_init(AUSOURCE_BUFFER_ARRAY, buf); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } compound_search(AUSEARCH_RULE_AND); compound_search(AUSEARCH_RULE_OR); auparse_destroy(au); printf("Test 7 Done\n\n"); printf("Starting Test 8, regex search...\n"); puts("Doing regex match..."); regex_search("1143146623"); puts("Doing regex wildcard search..."); regex_search("11431466.*146"); printf("Test 8 Done\n\n"); /* Note: this should match Test 2 exactly */ printf("Starting Test 9, buffer feed...\n"); { int event_cnt = 1; size_t len, chunk_len = 3; const char **cur_buf, *p_beg, *p_end, *p_chunk_beg, *p_chunk_end; au = auparse_init(AUSOURCE_FEED, 0); auparse_add_callback(au, auparse_callback, &event_cnt, NULL); for (cur_buf = buf, p_beg = *cur_buf; *cur_buf; cur_buf++, p_beg = *cur_buf) { len = strlen(p_beg); p_end = p_beg + len; p_chunk_beg = p_beg; while (p_chunk_beg < p_end) { p_chunk_end = p_chunk_beg + chunk_len; if (p_chunk_end > p_end) p_chunk_end = p_end; //fwrite(p_chunk_beg, 1, // p_chunk_end-p_chunk_beg, stdout); auparse_feed(au, p_chunk_beg, p_chunk_end-p_chunk_beg); p_chunk_beg = p_chunk_end; } } auparse_flush_feed(au); auparse_destroy(au); } printf("Test 9 Done\n\n"); /* Note: this should match Test 4 exactly */ printf("Starting Test 10, file feed...\n"); { int *event_cnt = malloc(sizeof(int)); size_t len; char filename[] = "./test.log"; char buf[4]; FILE *fp; *event_cnt = 1; au = auparse_init(AUSOURCE_FEED, 0); auparse_add_callback(au, auparse_callback, event_cnt, free); if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "could not open '%s', %s\n", filename, strerror(errno)); return 1; } while ((len = fread(buf, 1, sizeof(buf), fp))) { auparse_feed(au, buf, len); } fclose(fp); auparse_flush_feed(au); auparse_destroy(au); } printf("Test 10 Done\n\n"); printf("Starting Test 11, walk LONG event records from a file...\n"); au = auparse_init(AUSOURCE_FILE, "test4.log"); if (au == NULL) { printf("Error - %s\n", strerror(errno)); return 1; } walked_fields = 0; walk_test(au); auparse_destroy(au); if (walked_fields != FIELDS_EXPECTED) { printf("Error: %i fields expected, but %i read!\n", FIELDS_EXPECTED, walked_fields); } printf("Test 11 Done\n\n"); puts("Finished non-admin tests\n"); return 0; } audit-userspace-4.0.5/auparse/test/auparse_test.py000077500000000000000000000233471501761310600223220ustar00rootroot00000000000000#!/usr/bin/env python3 import os srcdir = os.getenv('srcdir') buf = ["type=LOGIN msg=audit(1143146623.787:142): login pid=2027 uid=0 old auid=4294967295 new auid=848\ntype=SYSCALL msg=audit(1143146623.875:143): arch=c000003e syscall=188 success=yes exit=0 a0=7fffffa9a9f0 a1=3958d11333 a2=5131f0 a3=20 items=1 pid=2027 auid=848 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=tty3 comm=\"login\" exe=\"/bin/login\" subj=system_u:system_r:local_login_t:s0-s0:c0.c255\n", "type=USER_LOGIN msg=audit(1143146623.879:146): user pid=2027 uid=0 auid=848 msg=\'uid=848: exe=\"/bin/login\" (hostname=?, addr=?, terminal=tty3 res=success)\'\n", ] files = ["%s%s" % (srcdir,"/test2.log"), "%s%s" % (srcdir,"/test.log")] import sys import time load_path = '../../bindings/python/python3' if False: sys.path.insert(0, load_path) import auparse def none_to_null(s): 'used so output matches C version' if s is None: return '(null)' else: return s walked_fields = 0 FIELDS_EXPECTED = 403 def walk_test(au): global walked_fields event_cnt = 1 au.reset() if not au.first_record(): print("Error getting first record") sys.exit(1) while True: print("event %d has %d records" % (event_cnt, au.get_num_records())) record_cnt = 1 while True: print(" record %d of type %d(%s) has %d fields" % \ (record_cnt, au.get_type(), au.get_type_name(), au.get_num_fields())) print(" line=%d file=%s" % (au.get_line_number(), au.get_filename())) event = au.get_timestamp() if event is None: print("Error getting timestamp - aborting") sys.exit(1) print(" event time: %d.%d:%d, host=%s" % (event.sec, event.milli, event.serial, none_to_null(event.host))) au.first_field() while True: print(" %s=%s (%s)" % (au.get_field_name(), au.get_field_str(), au.interpret_field())) walked_fields += 1 if not au.next_field(): break print("") record_cnt += 1 if not au.next_record(): break event_cnt += 1 if not au.parse_next_event(): break def light_test(au): while True: if not au.first_record(): print("Error getting first record") sys.exit(1) print("event has %d records" % (au.get_num_records())) record_cnt = 1 while True: print(" record %d of type %d(%s) has %d fields" % \ (record_cnt, au.get_type(), au.get_type_name(), au.get_num_fields())) print(" line=%d file=%s" % (au.get_line_number(), au.get_filename())) event = au.get_timestamp() if event is None: print("Error getting timestamp - aborting") sys.exit(1) print(" event time: %d.%d:%d, host=%s" % (event.sec, event.milli, event.serial, none_to_null(event.host))) print("") record_cnt += 1 if not au.next_record(): break if not au.parse_next_event(): break def simple_search(au, source, where): if source == auparse.AUSOURCE_FILE: au = auparse.AuParser(auparse.AUSOURCE_FILE, srcdir + "/test.log"); val = "4294967295" else: au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) val = "848" au.search_add_item("auid", "=", val, auparse.AUSEARCH_RULE_CLEAR) au.search_set_stop(where) if not au.search_next_event(): print("Error searching for auid") else: print("Found %s = %s" % (au.get_field_name(), au.get_field_str())) def compound_search(au, how): au = auparse.AuParser(auparse.AUSOURCE_FILE, srcdir + "/test.log"); if how == auparse.AUSEARCH_RULE_AND: au.search_add_item("uid", "=", "0", auparse.AUSEARCH_RULE_CLEAR) au.search_add_item("pid", "=", "13015", how) au.search_add_item("type", "=", "USER_START", how) else: au.search_add_item("auid", "=", "42", auparse.AUSEARCH_RULE_CLEAR) # should stop on this one au.search_add_item("auid", "=", "0", how) au.search_add_item("auid", "=", "500", how) au.search_set_stop(auparse.AUSEARCH_STOP_FIELD) if not au.search_next_event(): print("Error searching for auid") else: print("Found %s = %s" % (au.get_field_name(), au.get_field_str())) def feed_callback(au, cb_event_type, event_cnt): if cb_event_type == auparse.AUPARSE_CB_EVENT_READY: if not au.first_record(): print("Error getting first record") sys.exit(1) print("event %d has %d records" % (event_cnt[0], au.get_num_records())) record_cnt = 1 while True: print(" record %d of type %d(%s) has %d fields" % \ (record_cnt, au.get_type(), au.get_type_name(), au.get_num_fields())) print(" line=%d file=%s" % (au.get_line_number(), au.get_filename())) event = au.get_timestamp() if event is None: print("Error getting timestamp - aborting") sys.exit(1) print(" event time: %d.%d:%d, host=%s" % (event.sec, event.milli, event.serial, none_to_null(event.host))) au.first_field() while True: print(" %s=%s (%s)" % (au.get_field_name(), au.get_field_str(), au.interpret_field())) if not au.next_field(): break print("") record_cnt += 1 if not au.next_record(): break event_cnt[0] += 1 au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) print("Starting Test 1, iterate...") while au.parse_next_event(): if au.find_field("auid"): print("%s=%s" % (au.get_field_name(), au.get_field_str())) print("interp auid=%s" % (au.interpret_field())) else: print("Error iterating to auid") print("Test 1 Done\n") # Reset, now lets go to beginning and walk the list manually */ print("Starting Test 2, walk events, records, and fields...") walk_test(au) print("Test 2 Done\n") # Reset, now lets go to beginning and walk the list manually */ print("Starting Test 3, walk events, records of 1 buffer...") au = auparse.AuParser(auparse.AUSOURCE_BUFFER, buf[1]) au.reset() light_test(au); print("Test 3 Done\n") print("Starting Test 4, walk events, records of 1 file...") file1 = "%s%s" % (srcdir,"/test.log") au = auparse.AuParser(auparse.AUSOURCE_FILE, file1); walk_test(au); print("Test 4 Done\n") print("Starting Test 5, walk events, records of 2 files...") au = auparse.AuParser(auparse.AUSOURCE_FILE_ARRAY, files); walk_test(au); print("Test 5 Done\n") print("Starting Test 6, search...") au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) au.search_add_item("auid", "=", "500", auparse.AUSEARCH_RULE_CLEAR) au.search_set_stop(auparse.AUSEARCH_STOP_EVENT) if au.search_next_event(): print("Error search found something it shouldn't have") else: print("auid = 500 not found...which is correct") au.search_clear() au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) #au.search_add_item("auid", "exists", None, auparse.AUSEARCH_RULE_CLEAR) au.search_add_item("auid", "exists", "", auparse.AUSEARCH_RULE_CLEAR) au.search_set_stop(auparse.AUSEARCH_STOP_EVENT) if not au.search_next_event(): print("Error searching for existence of auid") print("auid exists...which is correct") print("Testing BUFFER_ARRAY, stop on field") simple_search(au, auparse.AUSOURCE_BUFFER_ARRAY, auparse.AUSEARCH_STOP_FIELD) print("Testing BUFFER_ARRAY, stop on record") simple_search(au, auparse.AUSOURCE_BUFFER_ARRAY, auparse.AUSEARCH_STOP_RECORD) print("Testing BUFFER_ARRAY, stop on event") simple_search(au, auparse.AUSOURCE_BUFFER_ARRAY, auparse.AUSEARCH_STOP_EVENT) print("Testing test.log, stop on field") simple_search(au, auparse.AUSOURCE_FILE, auparse.AUSEARCH_STOP_FIELD) print("Testing test.log, stop on record") simple_search(au, auparse.AUSOURCE_FILE, auparse.AUSEARCH_STOP_RECORD) print("Testing test.log, stop on event") simple_search(au, auparse.AUSOURCE_FILE, auparse.AUSEARCH_STOP_EVENT) print("Test 6 Done\n") print("Starting Test 7, compound search...") au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) compound_search(au, auparse.AUSEARCH_RULE_AND) compound_search(au, auparse.AUSEARCH_RULE_OR) print("Test 7 Done\n") print("Starting Test 8, regex search...") au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) print("Doing regex match...\n") au = auparse.AuParser(auparse.AUSOURCE_BUFFER_ARRAY, buf) print("Test 8 Done\n") # Note: this should match Test 2 exactly # Note: this should match Test 2 exactly print("Starting Test 9, buffer feed...") au = auparse.AuParser(auparse.AUSOURCE_FEED); event_cnt = 1 au.add_callback(feed_callback, [event_cnt]) chunk_len = 3 for s in buf: s_len = len(s) beg = 0 while beg < s_len: end = min(s_len, beg + chunk_len) data = s[beg:end] beg += chunk_len au.feed(data) au.flush_feed() print("Test 9 Done\n") # Note: this should match Test 4 exactly print("Starting Test 10, file feed...") au = auparse.AuParser(auparse.AUSOURCE_FEED); event_cnt = 1 au.add_callback(feed_callback, [event_cnt]) f = open(srcdir + "/test.log"); while True: data = f.read(4) if not data: break au.feed(data) au.flush_feed() print("Test 10 Done\n") print("Starting Test 11, walk LONG event records from a file...") au = auparse.AuParser(auparse.AUSOURCE_FILE, "test4.log"); walked_fields = 0 walk_test(au) if walked_fields != FIELDS_EXPECTED: print("Error: %i fields expected, but %i read!\n" % \ (FIELDS_EXPECTED, walked_fields)) print("Test 11 Done\n") print("Finished non-admin tests\n") au = None sys.exit(0) audit-userspace-4.0.5/auparse/test/auparse_test.ref000066400000000000000000001533071501761310600224430ustar00rootroot00000000000000Starting Test 1, iterate... auid=4294967295 interp auid=unset auid=848 interp auid=unknown(848) auid=848 interp auid=unknown(848) auid=4294967295 interp auid=unset auid=848 interp auid=unknown(848) auid=848 interp auid=unknown(848) auid=848 interp auid=unknown(848) Test 1 Done Starting Test 2, walk events, records, and fields... event 1 has 1 records record 1 of type 1006(LOGIN) has 5 fields line=1 file=None event time: 1143146623.787:142, host=? type=LOGIN (LOGIN) pid=2027 (2027) uid=0 (root) auid=4294967295 (unset) auid=848 (unknown(848)) event 2 has 1 records record 1 of type 1300(SYSCALL) has 24 fields line=2 file=None event time: 1143146623.875:143, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=188 (setxattr) success=yes (yes) exit=0 (0) a0=7fffffa9a9f0 (0x7fffffa9a9f0) a1=3958d11333 (0x3958d11333) a2=5131f0 (0x5131f0) a3=20 (0x20) items=1 (1) pid=2027 (2027) auid=848 (unknown(848)) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=tty3 (tty3) comm="login" (login) exe="/bin/login" (/bin/login) subj=system_u:system_r:local_login_t:s0-s0:c0.c255 (system_u:system_r:local_login_t:s0-s0:c0.c255) event 3 has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=3 file=None event time: 1143146623.879:146, host=? type=USER_LOGIN (USER_LOGIN) pid=2027 (2027) uid=0 (root) auid=848 (unknown(848)) uid=848 (unknown(848)) exe="/bin/login" (/bin/login) hostname=? (?) addr=? (?) terminal=tty3 (tty3) res=success (success) Test 2 Done Starting Test 3, walk events, records of 1 buffer... event has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=1 file=None event time: 1143146623.879:146, host=? Test 3 Done Starting Test 4, walk events, records of 1 file... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=./test.log event time: 1170021493.977:293, host=? type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=./test.log event time: 1170021493.977:293, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=./test.log event time: 1170021493.977:293, host=? type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=./test.log event time: 1170021493.977:293, host=? type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=./test.log event time: 1170021601.340:294, host=? type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=./test.log event time: 1170021601.342:295, host=? type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=./test.log event time: 1170021601.343:296, host=? type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=./test.log event time: 1170021601.343:296, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=./test.log event time: 1170021601.343:296, host=? type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=./test.log event time: 1170021601.344:297, host=? type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=./test.log event time: 1170021601.364:298, host=? type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=./test.log event time: 1170021601.366:299, host=? type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 4 Done Starting Test 5, walk events, records of 2 files... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=test2.log event time: 1170021493.977:283, host=? type=AVC (AVC) seresult=denied (denied) seperms=read (read) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=test2.log event time: 1170021493.977:283, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=test2.log event time: 1170021493.977:283, host=? type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=test2.log event time: 1170021493.977:283, host=? type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=test2.log event time: 1170021601.340:284, host=? type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=test2.log event time: 1170021601.342:285, host=? type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=test2.log event time: 1170021601.343:286, host=? type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=test2.log event time: 1170021601.343:286, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=test2.log event time: 1170021601.343:286, host=? type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=test2.log event time: 1170021601.344:287, host=? type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=test2.log event time: 1170021601.364:288, host=? type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=test2.log event time: 1170021601.366:289, host=? type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 8 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=test.log event time: 1170021493.977:293, host=? type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=test.log event time: 1170021493.977:293, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=test.log event time: 1170021493.977:293, host=? type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=test.log event time: 1170021493.977:293, host=? type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 9 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=test.log event time: 1170021601.340:294, host=? type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 10 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=test.log event time: 1170021601.342:295, host=? type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 11 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=test.log event time: 1170021601.343:296, host=? type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=test.log event time: 1170021601.343:296, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=test.log event time: 1170021601.343:296, host=? type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 12 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=test.log event time: 1170021601.344:297, host=? type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 13 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=test.log event time: 1170021601.364:298, host=? type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 14 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=test.log event time: 1170021601.366:299, host=? type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 5 Done Starting Test 6, search... auid = 500 not found...which is correct auid exists...which is correct Testing BUFFER_ARRAY, stop on field Found auid = 848 Testing BUFFER_ARRAY, stop on record Found type = SYSCALL Testing BUFFER_ARRAY, stop on event Found type = SYSCALL Testing test.log, stop on field Found auid = 4294967295 Testing test.log, stop on record Found type = SYSCALL Testing test.log, stop on event Found type = AVC Test 6 Done Starting Test 7, compound search... Found type = USER_START Found auid = 42 Test 7 Done Starting Test 8, regex search... Doing regex match... Found type = LOGIN Doing regex wildcard search... Found type = USER_LOGIN Test 8 Done Starting Test 9, buffer feed... event 1 has 1 records record 1 of type 1006(LOGIN) has 5 fields line=1 file=None event time: 1143146623.787:142, host=? type=LOGIN (LOGIN) pid=2027 (2027) uid=0 (root) auid=4294967295 (unset) auid=848 (unknown(848)) event 2 has 1 records record 1 of type 1300(SYSCALL) has 24 fields line=2 file=None event time: 1143146623.875:143, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=188 (setxattr) success=yes (yes) exit=0 (0) a0=7fffffa9a9f0 (0x7fffffa9a9f0) a1=3958d11333 (0x3958d11333) a2=5131f0 (0x5131f0) a3=20 (0x20) items=1 (1) pid=2027 (2027) auid=848 (unknown(848)) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=tty3 (tty3) comm="login" (login) exe="/bin/login" (/bin/login) subj=system_u:system_r:local_login_t:s0-s0:c0.c255 (system_u:system_r:local_login_t:s0-s0:c0.c255) event 3 has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=3 file=None event time: 1143146623.879:146, host=? type=USER_LOGIN (USER_LOGIN) pid=2027 (2027) uid=0 (root) auid=848 (unknown(848)) uid=848 (unknown(848)) exe="/bin/login" (/bin/login) hostname=? (?) addr=? (?) terminal=tty3 (tty3) res=success (success) Test 9 Done Starting Test 10, file feed... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=None event time: 1170021493.977:293, host=? type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=None event time: 1170021493.977:293, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=None event time: 1170021493.977:293, host=? type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=None event time: 1170021493.977:293, host=? type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=None event time: 1170021601.340:294, host=? type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=None event time: 1170021601.342:295, host=? type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=None event time: 1170021601.343:296, host=? type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=None event time: 1170021601.343:296, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=None event time: 1170021601.343:296, host=? type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=None event time: 1170021601.344:297, host=? type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=None event time: 1170021601.364:298, host=? type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=None event time: 1170021601.366:299, host=? type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 10 Done Starting Test 11, walk LONG event records from a file... event 1 has 7 records record 1 of type 1300(SYSCALL) has 26 fields line=1 file=test4.log event time: 1655465398.534:25618, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=59 (execve) success=yes (yes) exit=0 (0) a0=8c403a0 (0x8c403a0) a1=8c3e8b0 (0x8c3e8b0) a2=fffffb6cc5b0 (0xfffffb6cc5b0) a3=0 (0x0) items=3 (3) ppid=105182 (105182) pid=105183 (105183) auid=573 (unknown(573)) uid=583 (unknown(583)) gid=583 (unknown(583)) euid=583 (unknown(583)) suid=583 (unknown(583)) fsuid=583 (unknown(583)) egid=583 (unknown(583)) sgid=583 (unknown(583)) fsgid=583 (unknown(583)) tty=pts2 (pts2) ses=2632 (2632) comm="ld" (ld) exe="/bin/sh4" (/bin/sh4) key=(null) ((null)) record 2 of type 1309(EXECVE) has 50 fields line=2 file=test4.log event time: 1655465398.534:25618, host=? type=EXECVE (EXECVE) argc=48 (48) a0="/bin/sh" (/bin/sh) a1="-efu" (-efu) a2="/usr/bin/ld" (/usr/bin/ld) a3="-plugin" (-plugin) a4="/usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so" (/usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so) a5="-plugin-opt=/usr/libexec/gcc/aarch64-alt-linux/8/lto-wrapper" (-plugin-opt=/usr/libexec/gcc/aarch64-alt-linux/8/lto-wrapper) a6="-plugin-opt=-fresolution=/usr/src/tmp/cchyHiZN.res" (-plugin-opt=-fresolution=/usr/src/tmp/cchyHiZN.res) a7="-plugin-opt=-pass-through=-lgcc" (-plugin-opt=-pass-through=-lgcc) a8="-plugin-opt=-pass-through=-lgcc_s" (-plugin-opt=-pass-through=-lgcc_s) a9="-plugin-opt=-pass-through=-lc" (-plugin-opt=-pass-through=-lc) a10="-plugin-opt=-pass-through=-lgcc" (-plugin-opt=-pass-through=-lgcc) a11="-plugin-opt=-pass-through=-lgcc_s" (-plugin-opt=-pass-through=-lgcc_s) a12="--build-id" (--build-id) a13="--no-add-needed" (--no-add-needed) a14="--eh-frame-hdr" (--eh-frame-hdr) a15="--hash-style=gnu" (--hash-style=gnu) a16="--as-needed" (--as-needed) a17="-shared" (-shared) a18="-X" (-X) a19="-EL" (-EL) a20="-maarch64linux" (-maarch64linux) a21="-o" (-o) a22="ztest105133.so" (ztest105133.so) a23="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crti.o" (/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crti.o) a24="/usr/lib64/gcc/aarch64-alt-linux/8/crtbeginS.o" (/usr/lib64/gcc/aarch64-alt-linux/8/crtbeginS.o) a25="-L/usr/lib64/gcc/aarch64-alt-linux/8" (-L/usr/lib64/gcc/aarch64-alt-linux/8) a26="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64" (-L/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64) a27="-L/lib/../lib64" (-L/lib/../lib64) a28="-L/usr/lib/../lib64" (-L/usr/lib/../lib64) a29="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../.." (-L/usr/lib64/gcc/aarch64-alt-linux/8/../../..) a30="-soname" (-soname) a31="libz.so.1" (libz.so.1) a32="--version-script" (--version-script) a33="zlib.map" (zlib.map) a34="ztest105133.o" (ztest105133.o) a35="-lgcc" (-lgcc) a36="--push-state" (--push-state) a37="--as-needed" (--as-needed) a38="-lgcc_s" (-lgcc_s) a39="--pop-state" (--pop-state) a40="-lc" (-lc) a41="-lgcc" (-lgcc) a42="--push-state" (--push-state) a43="--as-needed" (--as-needed) a44="-lgcc_s" (-lgcc_s) a45="--pop-state" (--pop-state) a46="/usr/lib64/gcc/aarch64-alt-linux/8/crtendS.o" (/usr/lib64/gcc/aarch64-alt-linux/8/crtendS.o) a47="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crtn.o" (/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crtn.o) record 3 of type 1307(CWD) has 2 fields line=3 file=test4.log event time: 1655465398.534:25618, host=? type=CWD (CWD) cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1" (/usr/src/RPM/BUILD/zlib-1.2.11-alt1) record 4 of type 1302(PATH) has 15 fields line=4 file=test4.log event time: 1655465398.534:25618, host=? type=PATH (PATH) item=0 (0) name="/usr/bin/ld" (/usr/bin/ld) inode=40854 (40854) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 5 of type 1302(PATH) has 15 fields line=5 file=test4.log event time: 1655465398.534:25618, host=? type=PATH (PATH) item=1 (1) name="/bin/sh" (/bin/sh) inode=33238 (33238) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 6 of type 1302(PATH) has 15 fields line=6 file=test4.log event time: 1655465398.534:25618, host=? type=PATH (PATH) item=2 (2) name="/lib64/ld-linux-aarch64.so.1" (/lib64/ld-linux-aarch64.so.1) inode=33874 (33874) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 7 of type 1327(PROCTITLE) has 2 fields line=7 file=test4.log event time: 1655465398.534:25618, host=? type=PROCTITLE (PROCTITLE) proctitle=2F62696E2F7368002D656675002F7573722F62696E2F6C64002D706C7567696E002F7573722F6C6962657865632F6763632F616172636836342D616C742D6C696E75782F382F6C69626C746F5F706C7567696E2E736F002D706C7567696E2D6F70743D2F7573722F6C6962657865632F6763632F616172636836342D616C742D (/bin/sh -efu /usr/bin/ld -plugin /usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/aarch64-alt-) event 2 has 6 records record 1 of type 1300(SYSCALL) has 26 fields line=8 file=test4.log event time: 1655465404.819:27091, host=? type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=59 (execve) success=yes (yes) exit=0 (0) a0=1a407f50 (0x1a407f50) a1=1a401cd0 (0x1a401cd0) a2=1a3ed090 (0x1a3ed090) a3=0 (0x0) items=2 (2) ppid=105932 (105932) pid=105933 (105933) auid=573 (unknown(573)) uid=583 (unknown(583)) gid=583 (unknown(583)) euid=583 (unknown(583)) suid=583 (unknown(583)) fsuid=583 (unknown(583)) egid=583 (unknown(583)) sgid=583 (unknown(583)) fsgid=583 (unknown(583)) tty=pts2 (pts2) ses=2632 (2632) comm="m4" (m4) exe="/usr/bin/m4" (/usr/bin/m4) key=(null) ((null)) record 2 of type 1309(EXECVE) has 218 fields line=9 file=test4.log event time: 1655465404.819:27091, host=? type=EXECVE (EXECVE) argc=216 (216) a0="/usr/bin/m4" (/usr/bin/m4) a1="--nesting-limit=1024" (--nesting-limit=1024) a2="--gnu" (--gnu) a3="--include=/usr/share/autoconf-2.60" (--include=/usr/share/autoconf-2.60) a4="--debug=aflq" (--debug=aflq) a5="--fatal-warning" (--fatal-warning) a6="--debugfile=autom4te.cache/traces.0t" (--debugfile=autom4te.cache/traces.0t) a7="--trace=AC_CHECK_LIBM" (--trace=AC_CHECK_LIBM) a8="--trace=AC_CONFIG_MACRO_DIR" (--trace=AC_CONFIG_MACRO_DIR) a9="--trace=AC_CONFIG_MACRO_DIR_TRACE" (--trace=AC_CONFIG_MACRO_DIR_TRACE) a10="--trace=AC_DEFUN" (--trace=AC_DEFUN) a11="--trace=AC_DEFUN_ONCE" (--trace=AC_DEFUN_ONCE) a12="--trace=AC_DEPLIBS_CHECK_METHOD" (--trace=AC_DEPLIBS_CHECK_METHOD) a13="--trace=AC_DISABLE_FAST_INSTALL" (--trace=AC_DISABLE_FAST_INSTALL) a14="--trace=AC_DISABLE_SHARED" (--trace=AC_DISABLE_SHARED) a15="--trace=AC_DISABLE_STATIC" (--trace=AC_DISABLE_STATIC) a16="--trace=AC_ENABLE_FAST_INSTALL" (--trace=AC_ENABLE_FAST_INSTALL) a17="--trace=AC_ENABLE_SHARED" (--trace=AC_ENABLE_SHARED) a18="--trace=AC_ENABLE_STATIC" (--trace=AC_ENABLE_STATIC) a19="--trace=AC_LIBLTDL_CONVENIENCE" (--trace=AC_LIBLTDL_CONVENIENCE) a20="--trace=AC_LIBLTDL_INSTALLABLE" (--trace=AC_LIBLTDL_INSTALLABLE) a21="--trace=AC_LIBTOOL_COMPILER_OPTION" (--trace=AC_LIBTOOL_COMPILER_OPTION) a22="--trace=AC_LIBTOOL_CONFIG" (--trace=AC_LIBTOOL_CONFIG) a23="--trace=AC_LIBTOOL_CXX" (--trace=AC_LIBTOOL_CXX) a24="--trace=AC_LIBTOOL_DLOPEN" (--trace=AC_LIBTOOL_DLOPEN) a25="--trace=AC_LIBTOOL_DLOPEN_SELF" (--trace=AC_LIBTOOL_DLOPEN_SELF) a26="--trace=AC_LIBTOOL_F77" (--trace=AC_LIBTOOL_F77) a27="--trace=AC_LIBTOOL_FC" (--trace=AC_LIBTOOL_FC) a28="--trace=AC_LIBTOOL_GCJ" (--trace=AC_LIBTOOL_GCJ) a29="--trace=AC_LIBTOOL_LANG_CXX_CONFIG" (--trace=AC_LIBTOOL_LANG_CXX_CONFIG) a30="--trace=AC_LIBTOOL_LANG_C_CONFIG" (--trace=AC_LIBTOOL_LANG_C_CONFIG) a31="--trace=AC_LIBTOOL_LANG_F77_CONFIG" (--trace=AC_LIBTOOL_LANG_F77_CONFIG) a32="--trace=AC_LIBTOOL_LANG_GCJ_CONFIG" (--trace=AC_LIBTOOL_LANG_GCJ_CONFIG) a33="--trace=AC_LIBTOOL_LANG_RC_CONFIG" (--trace=AC_LIBTOOL_LANG_RC_CONFIG) a34="--trace=AC_LIBTOOL_LINKER_OPTION" (--trace=AC_LIBTOOL_LINKER_OPTION) a35="--trace=AC_LIBTOOL_OBJDIR" (--trace=AC_LIBTOOL_OBJDIR) a36="--trace=AC_LIBTOOL_PICMODE" (--trace=AC_LIBTOOL_PICMODE) a37="--trace=AC_LIBTOOL_POSTDEP_PREDEP" (--trace=AC_LIBTOOL_POSTDEP_PREDEP) a38="--trace=AC_LIBTOOL_PROG_CC_C_O" (--trace=AC_LIBTOOL_PROG_CC_C_O) a39="--trace=AC_LIBTOOL_PROG_COMPILER_NO_RTTI" (--trace=AC_LIBTOOL_PROG_COMPILER_NO_RTTI) a40="--trace=AC_LIBTOOL_PROG_COMPILER_PIC" (--trace=AC_LIBTOOL_PROG_COMPILER_PIC) a41="--trace=AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH" (--trace=AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH) a42="--trace=AC_LIBTOOL_PROG_LD_SHLIBS" (--trace=AC_LIBTOOL_PROG_LD_SHLIBS) a43="--trace=AC_LIBTOOL_RC" (--trace=AC_LIBTOOL_RC) a44="--trace=AC_LIBTOOL_SETUP" (--trace=AC_LIBTOOL_SETUP) a45="--trace=AC_LIBTOOL_SYS_DYNAMIC_LINKER" (--trace=AC_LIBTOOL_SYS_DYNAMIC_LINKER) a46="--trace=AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE" (--trace=AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE) a47="--trace=AC_LIBTOOL_SYS_HARD_LINK_LOCKS" (--trace=AC_LIBTOOL_SYS_HARD_LINK_LOCKS) a48="--trace=AC_LIBTOOL_SYS_LIB_STRIP" (--trace=AC_LIBTOOL_SYS_LIB_STRIP) a49="--trace=AC_LIBTOOL_SYS_MAX_CMD_LEN" (--trace=AC_LIBTOOL_SYS_MAX_CMD_LEN) a50="--trace=AC_LIBTOOL_SYS_OLD_ARCHIVE" (--trace=AC_LIBTOOL_SYS_OLD_ARCHIVE) a51="--trace=AC_LIBTOOL_WIN32_DLL" (--trace=AC_LIBTOOL_WIN32_DLL) a52="--trace=AC_LIB_LTDL" (--trace=AC_LIB_LTDL) a53="--trace=AC_LTDL_DLLIB" (--trace=AC_LTDL_DLLIB) a54="--trace=AC_LTDL_DLSYM_USCORE" (--trace=AC_LTDL_DLSYM_USCORE) a55="--trace=AC_LTDL_ENABLE_INSTALL" (--trace=AC_LTDL_ENABLE_INSTALL) a56="--trace=AC_LTDL_OBJDIR" (--trace=AC_LTDL_OBJDIR) a57="--trace=AC_LTDL_PREOPEN" (--trace=AC_LTDL_PREOPEN) a58="--trace=AC_LTDL_SHLIBEXT" (--trace=AC_LTDL_SHLIBEXT) a59="--trace=AC_LTDL_SHLIBPATH" (--trace=AC_LTDL_SHLIBPATH) a60="--trace=AC_LTDL_SYMBOL_USCORE" (--trace=AC_LTDL_SYMBOL_USCORE) a61="--trace=AC_LTDL_SYSSEARCHPATH" (--trace=AC_LTDL_SYSSEARCHPATH) a62="--trace=AC_LTDL_SYS_DLOPEN_DEPLIBS" (--trace=AC_LTDL_SYS_DLOPEN_DEPLIBS) a63="--trace=AC_PATH_MAGIC" (--trace=AC_PATH_MAGIC) a64="--trace=AC_PATH_TOOL_PREFIX" (--trace=AC_PATH_TOOL_PREFIX) a65="--trace=AC_PROG_EGREP" (--trace=AC_PROG_EGREP) a66="--trace=AC_PROG_LD" (--trace=AC_PROG_LD) a67="--trace=AC_PROG_LD_GNU" (--trace=AC_PROG_LD_GNU) a68="--trace=AC_PROG_LD_RELOAD_FLAG" (--trace=AC_PROG_LD_RELOAD_FLAG) a69="--trace=AC_PROG_LIBTOOL" (--trace=AC_PROG_LIBTOOL) a70="--trace=AC_PROG_NM" (--trace=AC_PROG_NM) a71="--trace=AC_WITH_LTDL" (--trace=AC_WITH_LTDL) a72="--trace=AM_AUTOMAKE_VERSION" (--trace=AM_AUTOMAKE_VERSION) a73="--trace=AM_AUX_DIR_EXPAND" (--trace=AM_AUX_DIR_EXPAND) a74="--trace=AM_CONDITIONAL" (--trace=AM_CONDITIONAL) a75="--trace=AM_DEP_TRACK" (--trace=AM_DEP_TRACK) a76="--trace=AM_DISABLE_SHARED" (--trace=AM_DISABLE_SHARED) a77="--trace=AM_DISABLE_STATIC" (--trace=AM_DISABLE_STATIC) a78="--trace=AM_ENABLE_SHARED" (--trace=AM_ENABLE_SHARED) a79="--trace=AM_ENABLE_STATIC" (--trace=AM_ENABLE_STATIC) a80="--trace=AM_INIT_AUTOMAKE" (--trace=AM_INIT_AUTOMAKE) a81="--trace=AM_MAKE_INCLUDE" (--trace=AM_MAKE_INCLUDE) a82="--trace=AM_MISSING_HAS_RUN" (--trace=AM_MISSING_HAS_RUN) a83="--trace=AM_MISSING_PROG" (--trace=AM_MISSING_PROG) a84="--trace=AM_OUTPUT_DEPENDENCY_COMMANDS" (--trace=AM_OUTPUT_DEPENDENCY_COMMANDS) a85="--trace=AM_PROG_CC_C_O" (--trace=AM_PROG_CC_C_O) a86="--trace=AM_PROG_INSTALL_SH" (--trace=AM_PROG_INSTALL_SH) a87="--trace=AM_PROG_INSTALL_STRIP" (--trace=AM_PROG_INSTALL_STRIP) a88="--trace=AM_PROG_LD" (--trace=AM_PROG_LD) a89="--trace=AM_PROG_LIBTOOL" (--trace=AM_PROG_LIBTOOL) a90="--trace=AM_PROG_NM" (--trace=AM_PROG_NM) a91="--trace=AM_RUN_LOG" (--trace=AM_RUN_LOG) a92="--trace=AM_SANITY_CHECK" (--trace=AM_SANITY_CHECK) a93="--trace=AM_SET_CURRENT_AUTOMAKE_VERSION" (--trace=AM_SET_CURRENT_AUTOMAKE_VERSION) a94="--trace=AM_SET_DEPDIR" (--trace=AM_SET_DEPDIR) a95="--trace=AM_SET_LEADING_DOT" (--trace=AM_SET_LEADING_DOT) a96="--trace=AM_SILENT_RULES" (--trace=AM_SILENT_RULES) a97="--trace=AM_SUBST_NOTMAKE" (--trace=AM_SUBST_NOTMAKE) a98="--trace=AU_DEFUN" (--trace=AU_DEFUN) a99="--trace=LTDL_CONVENIENCE" (--trace=LTDL_CONVENIENCE) a100="--trace=LTDL_INIT" (--trace=LTDL_INIT) a101="--trace=LTDL_INSTALLABLE" (--trace=LTDL_INSTALLABLE) a102="--trace=LTOBSOLETE_VERSION" (--trace=LTOBSOLETE_VERSION) a103="--trace=LTOPTIONS_VERSION" (--trace=LTOPTIONS_VERSION) a104="--trace=LTSUGAR_VERSION" (--trace=LTSUGAR_VERSION) a105="--trace=LTVERSION_VERSION" (--trace=LTVERSION_VERSION) a106="--trace=LT_AC_PROG_EGREP" (--trace=LT_AC_PROG_EGREP) a107="--trace=LT_AC_PROG_GCJ" (--trace=LT_AC_PROG_GCJ) a108="--trace=LT_AC_PROG_RC" (--trace=LT_AC_PROG_RC) a109="--trace=LT_AC_PROG_SED" (--trace=LT_AC_PROG_SED) a110="--trace=LT_CMD_MAX_LEN" (--trace=LT_CMD_MAX_LEN) a111="--trace=LT_CONFIG_LTDL_DIR" (--trace=LT_CONFIG_LTDL_DIR) a112="--trace=LT_FUNC_ARGZ" (--trace=LT_FUNC_ARGZ) a113="--trace=LT_FUNC_DLSYM_USCORE" (--trace=LT_FUNC_DLSYM_USCORE) a114="--trace=LT_INIT" (--trace=LT_INIT) a115="--trace=LT_LANG" (--trace=LT_LANG) a116="--trace=LT_LIB_DLLOAD" (--trace=LT_LIB_DLLOAD) a117="--trace=LT_LIB_M" (--trace=LT_LIB_M) a118="--trace=LT_OUTPUT" (--trace=LT_OUTPUT) a119="--trace=LT_PATH_LD" (--trace=LT_PATH_LD) a120="--trace=LT_PATH_NM" (--trace=LT_PATH_NM) a121="--trace=LT_PROG_GCJ" (--trace=LT_PROG_GCJ) a122="--trace=LT_PROG_GO" (--trace=LT_PROG_GO) a123="--trace=LT_PROG_RC" (--trace=LT_PROG_RC) a124="--trace=LT_SUPPORTED_TAG" (--trace=LT_SUPPORTED_TAG) a125="--trace=LT_SYS_DLOPEN_DEPLIBS" (--trace=LT_SYS_DLOPEN_DEPLIBS) a126="--trace=LT_SYS_DLOPEN_SELF" (--trace=LT_SYS_DLOPEN_SELF) a127="--trace=LT_SYS_DLSEARCH_PATH" (--trace=LT_SYS_DLSEARCH_PATH) a128="--trace=LT_SYS_MODULE_EXT" (--trace=LT_SYS_MODULE_EXT) a129="--trace=LT_SYS_MODULE_PATH" (--trace=LT_SYS_MODULE_PATH) a130="--trace=LT_SYS_SYMBOL_USCORE" (--trace=LT_SYS_SYMBOL_USCORE) a131="--trace=LT_WITH_LTDL" (--trace=LT_WITH_LTDL) a132="--trace=_AC_AM_CONFIG_HEADER_HOOK" (--trace=_AC_AM_CONFIG_HEADER_HOOK) a133="--trace=_AC_PROG_LIBTOOL" (--trace=_AC_PROG_LIBTOOL) a134="--trace=_AM_AUTOCONF_VERSION" (--trace=_AM_AUTOCONF_VERSION) a135="--trace=_AM_CONFIG_MACRO_DIRS" (--trace=_AM_CONFIG_MACRO_DIRS) a136="--trace=_AM_DEPENDENCIES" (--trace=_AM_DEPENDENCIES) a137="--trace=_AM_IF_OPTION" (--trace=_AM_IF_OPTION) a138="--trace=_AM_MANGLE_OPTION" (--trace=_AM_MANGLE_OPTION) a139="--trace=_AM_OUTPUT_DEPENDENCY_COMMANDS" (--trace=_AM_OUTPUT_DEPENDENCY_COMMANDS) a140="--trace=_AM_PROG_CC_C_O" (--trace=_AM_PROG_CC_C_O) a141="--trace=_AM_PROG_TAR" (--trace=_AM_PROG_TAR) a142="--trace=_AM_SET_OPTION" (--trace=_AM_SET_OPTION) a143="--trace=_AM_SET_OPTIONS" (--trace=_AM_SET_OPTIONS) a144="--trace=_AM_SUBST_NOTMAKE" (--trace=_AM_SUBST_NOTMAKE) a145="--trace=_LTDL_SETUP" (--trace=_LTDL_SETUP) a146="--trace=_LT_AC_CHECK_DLFCN" (--trace=_LT_AC_CHECK_DLFCN) a147="--trace=_LT_AC_FILE_LTDLL_C" (--trace=_LT_AC_FILE_LTDLL_C) a148="--trace=_LT_AC_LANG_CXX" (--trace=_LT_AC_LANG_CXX) a149="--trace=_LT_AC_LANG_CXX_CONFIG" (--trace=_LT_AC_LANG_CXX_CONFIG) a150="--trace=_LT_AC_LANG_C_CONFIG" (--trace=_LT_AC_LANG_C_CONFIG) a151="--trace=_LT_AC_LANG_F77" (--trace=_LT_AC_LANG_F77) a152="--trace=_LT_AC_LANG_F77_CONFIG" (--trace=_LT_AC_LANG_F77_CONFIG) a153="--trace=_LT_AC_LANG_GCJ" (--trace=_LT_AC_LANG_GCJ) a154="--trace=_LT_AC_LANG_GCJ_CONFIG" (--trace=_LT_AC_LANG_GCJ_CONFIG) a155="--trace=_LT_AC_LANG_RC_CONFIG" (--trace=_LT_AC_LANG_RC_CONFIG) a156="--trace=_LT_AC_LOCK" (--trace=_LT_AC_LOCK) a157="--trace=_LT_AC_PROG_CXXCPP" (--trace=_LT_AC_PROG_CXXCPP) a158="--trace=_LT_AC_PROG_ECHO_BACKSLASH" (--trace=_LT_AC_PROG_ECHO_BACKSLASH) a159="--trace=_LT_AC_SHELL_INIT" (--trace=_LT_AC_SHELL_INIT) a160="--trace=_LT_AC_SYS_COMPILER" (--trace=_LT_AC_SYS_COMPILER) a161="--trace=_LT_AC_SYS_LIBPATH_AIX" (--trace=_LT_AC_SYS_LIBPATH_AIX) a162="--trace=_LT_AC_TAGCONFIG" (--trace=_LT_AC_TAGCONFIG) a163="--trace=_LT_AC_TAGVAR" (--trace=_LT_AC_TAGVAR) a164="--trace=_LT_AC_TRY_DLOPEN_SELF" (--trace=_LT_AC_TRY_DLOPEN_SELF) a165="--trace=_LT_CC_BASENAME" (--trace=_LT_CC_BASENAME) a166="--trace=_LT_COMPILER_BOILERPLATE" (--trace=_LT_COMPILER_BOILERPLATE) a167="--trace=_LT_COMPILER_OPTION" (--trace=_LT_COMPILER_OPTION) a168="--trace=_LT_DLL_DEF_P" (--trace=_LT_DLL_DEF_P) a169="--trace=_LT_LIBOBJ" (--trace=_LT_LIBOBJ) a170="--trace=_LT_LINKER_BOILERPLATE" (--trace=_LT_LINKER_BOILERPLATE) a171="--trace=_LT_LINKER_OPTION" (--trace=_LT_LINKER_OPTION) a172="--trace=_LT_PATH_TOOL_PREFIX" (--trace=_LT_PATH_TOOL_PREFIX) a173="--trace=_LT_PREPARE_SED_QUOTE_VARS" (--trace=_LT_PREPARE_SED_QUOTE_VARS) a174="--trace=_LT_PROG_CXX" (--trace=_LT_PROG_CXX) a175="--trace=_LT_PROG_ECHO_BACKSLASH" (--trace=_LT_PROG_ECHO_BACKSLASH) a176="--trace=_LT_PROG_F77" (--trace=_LT_PROG_F77) a177="--trace=_LT_PROG_FC" (--trace=_LT_PROG_FC) a178="--trace=_LT_PROG_LTMAIN" (--trace=_LT_PROG_LTMAIN) a179="--trace=_LT_REQUIRED_DARWIN_CHECKS" (--trace=_LT_REQUIRED_DARWIN_CHECKS) a180="--trace=_LT_WITH_SYSROOT" (--trace=_LT_WITH_SYSROOT) a181="--trace=_m4_warn" (--trace=_m4_warn) a182="--trace=include" (--trace=include) a183="--trace=m4_include" (--trace=m4_include) a184="--trace=m4_pattern_allow" (--trace=m4_pattern_allow) a185="--trace=m4_pattern_forbid" (--trace=m4_pattern_forbid) a186="--reload-state=/usr/share/autoconf-2.60/autoconf/autoconf.m4f" (--reload-state=/usr/share/autoconf-2.60/autoconf/autoconf.m4f) a187="--undefine=__m4_version__" (--undefine=__m4_version__) a188="-" (-) a189="/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4" (/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4) a190="/usr/share/libtool/aclocal/libtool.m4" (/usr/share/libtool/aclocal/libtool.m4) a191="/usr/share/libtool/aclocal/ltargz.m4" (/usr/share/libtool/aclocal/ltargz.m4) a192="/usr/share/libtool/aclocal/ltdl.m4" (/usr/share/libtool/aclocal/ltdl.m4) a193="/usr/share/libtool/aclocal/ltoptions.m4" (/usr/share/libtool/aclocal/ltoptions.m4) a194="/usr/share/libtool/aclocal/ltsugar.m4" (/usr/share/libtool/aclocal/ltsugar.m4) a195="/usr/share/libtool/aclocal/ltversion.m4" (/usr/share/libtool/aclocal/ltversion.m4) a196="/usr/share/libtool/aclocal/lt~obsolete.m4" (/usr/share/libtool/aclocal/lt~obsolete.m4) a197="/usr/share/aclocal-1.16/amversion.m4" (/usr/share/aclocal-1.16/amversion.m4) a198="/usr/share/aclocal-1.16/auxdir.m4" (/usr/share/aclocal-1.16/auxdir.m4) a199="/usr/share/aclocal-1.16/cond.m4" (/usr/share/aclocal-1.16/cond.m4) a200="/usr/share/aclocal-1.16/depend.m4" (/usr/share/aclocal-1.16/depend.m4) a201="/usr/share/aclocal-1.16/depout.m4" (/usr/share/aclocal-1.16/depout.m4) a202="/usr/share/aclocal-1.16/init.m4" (/usr/share/aclocal-1.16/init.m4) a203="/usr/share/aclocal-1.16/install-sh.m4" (/usr/share/aclocal-1.16/install-sh.m4) a204="/usr/share/aclocal-1.16/lead-dot.m4" (/usr/share/aclocal-1.16/lead-dot.m4) a205="/usr/share/aclocal-1.16/make.m4" (/usr/share/aclocal-1.16/make.m4) a206="/usr/share/aclocal-1.16/missing.m4" (/usr/share/aclocal-1.16/missing.m4) a207="/usr/share/aclocal-1.16/options.m4" (/usr/share/aclocal-1.16/options.m4) a208="/usr/share/aclocal-1.16/prog-cc-c-o.m4" (/usr/share/aclocal-1.16/prog-cc-c-o.m4) a209="/usr/share/aclocal-1.16/runlog.m4" (/usr/share/aclocal-1.16/runlog.m4) a210="/usr/share/aclocal-1.16/sanity.m4" (/usr/share/aclocal-1.16/sanity.m4) a211="/usr/share/aclocal-1.16/silent.m4" (/usr/share/aclocal-1.16/silent.m4) a212="/usr/share/aclocal-1.16/strip.m4" (/usr/share/aclocal-1.16/strip.m4) a213="/usr/share/aclocal-1.16/substnot.m4" (/usr/share/aclocal-1.16/substnot.m4) a214="/usr/share/aclocal-1.16/tar.m4" (/usr/share/aclocal-1.16/tar.m4) a215="configure.ac" (configure.ac) record 3 of type 1307(CWD) has 2 fields line=10 file=test4.log event time: 1655465404.819:27091, host=? type=CWD (CWD) cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1/contrib/minizip" (/usr/src/RPM/BUILD/zlib-1.2.11-alt1/contrib/minizip) record 4 of type 1302(PATH) has 15 fields line=11 file=test4.log event time: 1655465404.819:27091, host=? type=PATH (PATH) item=0 (0) name="/usr/bin/m4" (/usr/bin/m4) inode=40839 (40839) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 5 of type 1302(PATH) has 15 fields line=12 file=test4.log event time: 1655465404.819:27091, host=? type=PATH (PATH) item=1 (1) name="/lib64/ld-linux-aarch64.so.1" (/lib64/ld-linux-aarch64.so.1) inode=33874 (33874) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 6 of type 1327(PROCTITLE) has 2 fields line=13 file=test4.log event time: 1655465404.819:27091, host=? type=PROCTITLE (PROCTITLE) proctitle=2F7573722F62696E2F6D34002D2D6E657374696E672D6C696D69743D31303234002D2D676E75002D2D696E636C7564653D2F7573722F73686172652F6175746F636F6E662D322E3630002D2D64656275673D61666C71002D2D666174616C2D7761726E696E67002D2D646562756766696C653D6175746F6D3474652E63616368 (/usr/bin/m4 --nesting-limit=1024 --gnu --include=/usr/share/autoconf-2.60 --debug=aflq --fatal-warning --debugfile=autom4te.cach) Test 11 Done Finished non-admin tests audit-userspace-4.0.5/auparse/test/auparse_test.ref.py000066400000000000000000001534621501761310600230740ustar00rootroot00000000000000Starting Test 1, iterate... auid=4294967295 interp auid=unset auid=848 interp auid=unknown(848) auid=848 interp auid=unknown(848) Test 1 Done Starting Test 2, walk events, records, and fields... event 1 has 1 records record 1 of type 1006(LOGIN) has 5 fields line=1 file=None event time: 1143146623.787:142, host=(null) type=LOGIN (LOGIN) pid=2027 (2027) uid=0 (root) auid=4294967295 (unset) auid=848 (unknown(848)) event 2 has 1 records record 1 of type 1300(SYSCALL) has 24 fields line=2 file=None event time: 1143146623.875:143, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=188 (setxattr) success=yes (yes) exit=0 (0) a0=7fffffa9a9f0 (0x7fffffa9a9f0) a1=3958d11333 (0x3958d11333) a2=5131f0 (0x5131f0) a3=20 (0x20) items=1 (1) pid=2027 (2027) auid=848 (unknown(848)) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=tty3 (tty3) comm="login" (login) exe="/bin/login" (/bin/login) subj=system_u:system_r:local_login_t:s0-s0:c0.c255 (system_u:system_r:local_login_t:s0-s0:c0.c255) event 3 has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=3 file=None event time: 1143146623.879:146, host=(null) type=USER_LOGIN (USER_LOGIN) pid=2027 (2027) uid=0 (root) auid=848 (unknown(848)) uid=848 (unknown(848)) exe="/bin/login" (/bin/login) hostname=? (?) addr=? (?) terminal=tty3 (tty3) res=success (success) Test 2 Done Starting Test 3, walk events, records of 1 buffer... event has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=1 file=None event time: 1143146623.879:146, host=(null) Test 3 Done Starting Test 4, walk events, records of 1 file... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=test.log event time: 1170021493.977:293, host=(null) type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=test.log event time: 1170021493.977:293, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=test.log event time: 1170021493.977:293, host=(null) type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=test.log event time: 1170021493.977:293, host=(null) type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=test.log event time: 1170021601.340:294, host=(null) type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=test.log event time: 1170021601.342:295, host=(null) type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=test.log event time: 1170021601.343:296, host=(null) type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=test.log event time: 1170021601.343:296, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=test.log event time: 1170021601.343:296, host=(null) type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=test.log event time: 1170021601.344:297, host=(null) type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=test.log event time: 1170021601.364:298, host=(null) type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=test.log event time: 1170021601.366:299, host=(null) type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 4 Done Starting Test 5, walk events, records of 2 files... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=test2.log event time: 1170021493.977:283, host=(null) type=AVC (AVC) seresult=denied (denied) seperms=read (read) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=test2.log event time: 1170021493.977:283, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=test2.log event time: 1170021493.977:283, host=(null) type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=test2.log event time: 1170021493.977:283, host=(null) type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=test2.log event time: 1170021601.340:284, host=(null) type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=test2.log event time: 1170021601.342:285, host=(null) type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=test2.log event time: 1170021601.343:286, host=(null) type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=test2.log event time: 1170021601.343:286, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=test2.log event time: 1170021601.343:286, host=(null) type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=test2.log event time: 1170021601.344:287, host=(null) type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=test2.log event time: 1170021601.364:288, host=(null) type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=test2.log event time: 1170021601.366:289, host=(null) type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 8 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=test.log event time: 1170021493.977:293, host=(null) type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=test.log event time: 1170021493.977:293, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=test.log event time: 1170021493.977:293, host=(null) type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=test.log event time: 1170021493.977:293, host=(null) type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 9 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=test.log event time: 1170021601.340:294, host=(null) type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 10 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=test.log event time: 1170021601.342:295, host=(null) type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 11 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=test.log event time: 1170021601.343:296, host=(null) type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=test.log event time: 1170021601.343:296, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=test.log event time: 1170021601.343:296, host=(null) type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 12 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=test.log event time: 1170021601.344:297, host=(null) type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 13 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=test.log event time: 1170021601.364:298, host=(null) type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 14 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=test.log event time: 1170021601.366:299, host=(null) type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 5 Done Starting Test 6, search... auid = 500 not found...which is correct auid exists...which is correct Testing BUFFER_ARRAY, stop on field Found auid = 848 Testing BUFFER_ARRAY, stop on record Found type = SYSCALL Testing BUFFER_ARRAY, stop on event Found type = SYSCALL Testing test.log, stop on field Found auid = 4294967295 Testing test.log, stop on record Found type = SYSCALL Testing test.log, stop on event Found type = AVC Test 6 Done Starting Test 7, compound search... Found type = USER_START Found auid = 42 Test 7 Done Starting Test 8, regex search... Doing regex match... Test 8 Done Starting Test 9, buffer feed... event 1 has 1 records record 1 of type 1006(LOGIN) has 5 fields line=1 file=None event time: 1143146623.787:142, host=(null) type=LOGIN (LOGIN) pid=2027 (2027) uid=0 (root) auid=4294967295 (unset) auid=848 (unknown(848)) event 2 has 1 records record 1 of type 1300(SYSCALL) has 24 fields line=2 file=None event time: 1143146623.875:143, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=188 (setxattr) success=yes (yes) exit=0 (0) a0=7fffffa9a9f0 (0x7fffffa9a9f0) a1=3958d11333 (0x3958d11333) a2=5131f0 (0x5131f0) a3=20 (0x20) items=1 (1) pid=2027 (2027) auid=848 (unknown(848)) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=tty3 (tty3) comm="login" (login) exe="/bin/login" (/bin/login) subj=system_u:system_r:local_login_t:s0-s0:c0.c255 (system_u:system_r:local_login_t:s0-s0:c0.c255) event 3 has 1 records record 1 of type 1112(USER_LOGIN) has 10 fields line=3 file=None event time: 1143146623.879:146, host=(null) type=USER_LOGIN (USER_LOGIN) pid=2027 (2027) uid=0 (root) auid=848 (unknown(848)) uid=848 (unknown(848)) exe="/bin/login" (/bin/login) hostname=? (?) addr=? (?) terminal=tty3 (tty3) res=success (success) Test 9 Done Starting Test 10, file feed... event 1 has 4 records record 1 of type 1400(AVC) has 11 fields line=1 file=None event time: 1170021493.977:293, host=(null) type=AVC (AVC) seresult=denied (denied) seperms=read,write (read,write) pid=13010 (13010) comm="pickup" (pickup) name="maildrop" (maildrop) dev=hda7 (hda7) ino=14911367 (14911367) scontext=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) tclass=dir (dir) record 2 of type 1300(SYSCALL) has 26 fields line=2 file=None event time: 1170021493.977:293, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=2 (open) success=no (no) exit=-13 (EACCES(Permission denied)) a0=5555665d91b0 (0x5555665d91b0) a1=10800 (O_RDONLY|O_NONBLOCK|O_DIRECTORY) a2=5555665d91b8 (0x5555665d91b8) a3=0 (0x0) items=1 (1) ppid=2013 (2013) pid=13010 (13010) auid=4294967295 (unset) uid=890 (unknown(890)) gid=890 (unknown(890)) euid=890 (unknown(890)) suid=890 (unknown(890)) fsuid=890 (unknown(890)) egid=890 (unknown(890)) sgid=890 (unknown(890)) fsgid=890 (unknown(890)) tty=(none) ((none)) comm="pickup" (pickup) exe="/usr/libexec/postfix/pickup" (/usr/libexec/postfix/pickup) subj=system_u:system_r:postfix_pickup_t:s0 (system_u:system_r:postfix_pickup_t:s0) key=(null) ((null)) record 3 of type 1307(CWD) has 2 fields line=3 file=None event time: 1170021493.977:293, host=(null) type=CWD (CWD) cwd="/var/spool/postfix" (/var/spool/postfix) record 4 of type 1302(PATH) has 10 fields line=4 file=None event time: 1170021493.977:293, host=(null) type=PATH (PATH) item=0 (0) name="maildrop" (maildrop) inode=14911367 (14911367) dev=03:07 (03:07) mode=040730 (dir,730) ouid=890 (unknown(890)) ogid=891 (unknown(891)) rdev=00:00 (00:00) obj=system_u:object_r:postfix_spool_maildrop_t:s0 (system_u:object_r:postfix_spool_maildrop_t:s0) event 2 has 1 records record 1 of type 1101(USER_ACCT) has 11 fields line=5 file=None event time: 1170021601.340:294, host=(null) type=USER_ACCT (USER_ACCT) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 3 has 1 records record 1 of type 1103(CRED_ACQ) has 11 fields line=6 file=None event time: 1170021601.342:295, host=(null) type=CRED_ACQ (CRED_ACQ) pid=13015 (13015) uid=0 (root) auid=4294967295 (unset) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 4 has 3 records record 1 of type 1006(LOGIN) has 10 fields line=7 file=None event time: 1170021601.343:296, host=(null) type=LOGIN (LOGIN) pid=2288 (2288) uid=0 (root) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) old-auid=4294967295 (unset) auid=42 (gdm) tty=(none) ((none)) old-ses=4294967295 (4294967295) ses=1 (1) res=1 (yes) record 2 of type 1300(SYSCALL) has 27 fields line=8 file=None event time: 1170021601.343:296, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=1 (write) success=yes (yes) exit=2 (2) a0=8 (0x8) a1=7fffa7aede20 (0x7fffa7aede20) a2=2 (0x2) a3=0 (0x0) items=0 (0) ppid=1 (1) pid=2288 (2288) auid=42 (gdm) uid=0 (root) gid=0 (root) euid=0 (root) suid=0 (root) fsuid=0 (root) egid=0 (root) sgid=0 (root) fsgid=0 (root) tty=(none) ((none)) ses=1 (1) comm="(systemd)" ((systemd)) exe="/usr/lib/systemd/systemd" (/usr/lib/systemd/systemd) subj=system_u:system_r:init_t:s0 (system_u:system_r:init_t:s0) key=(null) ((null)) record 3 of type 1327(PROCTITLE) has 2 fields line=9 file=None event time: 1170021601.343:296, host=(null) type=PROCTITLE (PROCTITLE) proctitle="(systemd)" ((systemd)) event 5 has 1 records record 1 of type 1105(USER_START) has 11 fields line=10 file=None event time: 1170021601.344:297, host=(null) type=USER_START (USER_START) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 6 has 1 records record 1 of type 1104(CRED_DISP) has 11 fields line=11 file=None event time: 1170021601.364:298, host=(null) type=CRED_DISP (CRED_DISP) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) event 7 has 1 records record 1 of type 1106(USER_END) has 11 fields line=12 file=None event time: 1170021601.366:299, host=(null) type=USER_END (USER_END) pid=13015 (13015) uid=0 (root) auid=0 (root) subj=system_u:system_r:crond_t:s0-s0:c0.c1023 (system_u:system_r:crond_t:s0-s0:c0.c1023) acct=root (root) exe="/usr/sbin/crond" (/usr/sbin/crond) hostname=? (?) addr=? (?) terminal=cron (cron) res=success (success) Test 10 Done Starting Test 11, walk LONG event records from a file... event 1 has 7 records record 1 of type 1300(SYSCALL) has 26 fields line=1 file=test4.log event time: 1655465398.534:25618, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=59 (execve) success=yes (yes) exit=0 (0) a0=8c403a0 (0x8c403a0) a1=8c3e8b0 (0x8c3e8b0) a2=fffffb6cc5b0 (0xfffffb6cc5b0) a3=0 (0x0) items=3 (3) ppid=105182 (105182) pid=105183 (105183) auid=573 (unknown(573)) uid=583 (unknown(583)) gid=583 (unknown(583)) euid=583 (unknown(583)) suid=583 (unknown(583)) fsuid=583 (unknown(583)) egid=583 (unknown(583)) sgid=583 (unknown(583)) fsgid=583 (unknown(583)) tty=pts2 (pts2) ses=2632 (2632) comm="ld" (ld) exe="/bin/sh4" (/bin/sh4) key=(null) ((null)) record 2 of type 1309(EXECVE) has 50 fields line=2 file=test4.log event time: 1655465398.534:25618, host=(null) type=EXECVE (EXECVE) argc=48 (48) a0="/bin/sh" (/bin/sh) a1="-efu" (-efu) a2="/usr/bin/ld" (/usr/bin/ld) a3="-plugin" (-plugin) a4="/usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so" (/usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so) a5="-plugin-opt=/usr/libexec/gcc/aarch64-alt-linux/8/lto-wrapper" (-plugin-opt=/usr/libexec/gcc/aarch64-alt-linux/8/lto-wrapper) a6="-plugin-opt=-fresolution=/usr/src/tmp/cchyHiZN.res" (-plugin-opt=-fresolution=/usr/src/tmp/cchyHiZN.res) a7="-plugin-opt=-pass-through=-lgcc" (-plugin-opt=-pass-through=-lgcc) a8="-plugin-opt=-pass-through=-lgcc_s" (-plugin-opt=-pass-through=-lgcc_s) a9="-plugin-opt=-pass-through=-lc" (-plugin-opt=-pass-through=-lc) a10="-plugin-opt=-pass-through=-lgcc" (-plugin-opt=-pass-through=-lgcc) a11="-plugin-opt=-pass-through=-lgcc_s" (-plugin-opt=-pass-through=-lgcc_s) a12="--build-id" (--build-id) a13="--no-add-needed" (--no-add-needed) a14="--eh-frame-hdr" (--eh-frame-hdr) a15="--hash-style=gnu" (--hash-style=gnu) a16="--as-needed" (--as-needed) a17="-shared" (-shared) a18="-X" (-X) a19="-EL" (-EL) a20="-maarch64linux" (-maarch64linux) a21="-o" (-o) a22="ztest105133.so" (ztest105133.so) a23="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crti.o" (/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crti.o) a24="/usr/lib64/gcc/aarch64-alt-linux/8/crtbeginS.o" (/usr/lib64/gcc/aarch64-alt-linux/8/crtbeginS.o) a25="-L/usr/lib64/gcc/aarch64-alt-linux/8" (-L/usr/lib64/gcc/aarch64-alt-linux/8) a26="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64" (-L/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64) a27="-L/lib/../lib64" (-L/lib/../lib64) a28="-L/usr/lib/../lib64" (-L/usr/lib/../lib64) a29="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../.." (-L/usr/lib64/gcc/aarch64-alt-linux/8/../../..) a30="-soname" (-soname) a31="libz.so.1" (libz.so.1) a32="--version-script" (--version-script) a33="zlib.map" (zlib.map) a34="ztest105133.o" (ztest105133.o) a35="-lgcc" (-lgcc) a36="--push-state" (--push-state) a37="--as-needed" (--as-needed) a38="-lgcc_s" (-lgcc_s) a39="--pop-state" (--pop-state) a40="-lc" (-lc) a41="-lgcc" (-lgcc) a42="--push-state" (--push-state) a43="--as-needed" (--as-needed) a44="-lgcc_s" (-lgcc_s) a45="--pop-state" (--pop-state) a46="/usr/lib64/gcc/aarch64-alt-linux/8/crtendS.o" (/usr/lib64/gcc/aarch64-alt-linux/8/crtendS.o) a47="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crtn.o" (/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crtn.o) record 3 of type 1307(CWD) has 2 fields line=3 file=test4.log event time: 1655465398.534:25618, host=(null) type=CWD (CWD) cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1" (/usr/src/RPM/BUILD/zlib-1.2.11-alt1) record 4 of type 1302(PATH) has 15 fields line=4 file=test4.log event time: 1655465398.534:25618, host=(null) type=PATH (PATH) item=0 (0) name="/usr/bin/ld" (/usr/bin/ld) inode=40854 (40854) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 5 of type 1302(PATH) has 15 fields line=5 file=test4.log event time: 1655465398.534:25618, host=(null) type=PATH (PATH) item=1 (1) name="/bin/sh" (/bin/sh) inode=33238 (33238) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 6 of type 1302(PATH) has 15 fields line=6 file=test4.log event time: 1655465398.534:25618, host=(null) type=PATH (PATH) item=2 (2) name="/lib64/ld-linux-aarch64.so.1" (/lib64/ld-linux-aarch64.so.1) inode=33874 (33874) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 7 of type 1327(PROCTITLE) has 2 fields line=7 file=test4.log event time: 1655465398.534:25618, host=(null) type=PROCTITLE (PROCTITLE) proctitle=2F62696E2F7368002D656675002F7573722F62696E2F6C64002D706C7567696E002F7573722F6C6962657865632F6763632F616172636836342D616C742D6C696E75782F382F6C69626C746F5F706C7567696E2E736F002D706C7567696E2D6F70743D2F7573722F6C6962657865632F6763632F616172636836342D616C742D (/bin/sh -efu /usr/bin/ld -plugin /usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so -plugin-opt=/usr/libexec/gcc/aarch64-alt-) event 2 has 6 records record 1 of type 1300(SYSCALL) has 26 fields line=8 file=test4.log event time: 1655465404.819:27091, host=(null) type=SYSCALL (SYSCALL) arch=c000003e (x86_64) syscall=59 (execve) success=yes (yes) exit=0 (0) a0=1a407f50 (0x1a407f50) a1=1a401cd0 (0x1a401cd0) a2=1a3ed090 (0x1a3ed090) a3=0 (0x0) items=2 (2) ppid=105932 (105932) pid=105933 (105933) auid=573 (unknown(573)) uid=583 (unknown(583)) gid=583 (unknown(583)) euid=583 (unknown(583)) suid=583 (unknown(583)) fsuid=583 (unknown(583)) egid=583 (unknown(583)) sgid=583 (unknown(583)) fsgid=583 (unknown(583)) tty=pts2 (pts2) ses=2632 (2632) comm="m4" (m4) exe="/usr/bin/m4" (/usr/bin/m4) key=(null) ((null)) record 2 of type 1309(EXECVE) has 218 fields line=9 file=test4.log event time: 1655465404.819:27091, host=(null) type=EXECVE (EXECVE) argc=216 (216) a0="/usr/bin/m4" (/usr/bin/m4) a1="--nesting-limit=1024" (--nesting-limit=1024) a2="--gnu" (--gnu) a3="--include=/usr/share/autoconf-2.60" (--include=/usr/share/autoconf-2.60) a4="--debug=aflq" (--debug=aflq) a5="--fatal-warning" (--fatal-warning) a6="--debugfile=autom4te.cache/traces.0t" (--debugfile=autom4te.cache/traces.0t) a7="--trace=AC_CHECK_LIBM" (--trace=AC_CHECK_LIBM) a8="--trace=AC_CONFIG_MACRO_DIR" (--trace=AC_CONFIG_MACRO_DIR) a9="--trace=AC_CONFIG_MACRO_DIR_TRACE" (--trace=AC_CONFIG_MACRO_DIR_TRACE) a10="--trace=AC_DEFUN" (--trace=AC_DEFUN) a11="--trace=AC_DEFUN_ONCE" (--trace=AC_DEFUN_ONCE) a12="--trace=AC_DEPLIBS_CHECK_METHOD" (--trace=AC_DEPLIBS_CHECK_METHOD) a13="--trace=AC_DISABLE_FAST_INSTALL" (--trace=AC_DISABLE_FAST_INSTALL) a14="--trace=AC_DISABLE_SHARED" (--trace=AC_DISABLE_SHARED) a15="--trace=AC_DISABLE_STATIC" (--trace=AC_DISABLE_STATIC) a16="--trace=AC_ENABLE_FAST_INSTALL" (--trace=AC_ENABLE_FAST_INSTALL) a17="--trace=AC_ENABLE_SHARED" (--trace=AC_ENABLE_SHARED) a18="--trace=AC_ENABLE_STATIC" (--trace=AC_ENABLE_STATIC) a19="--trace=AC_LIBLTDL_CONVENIENCE" (--trace=AC_LIBLTDL_CONVENIENCE) a20="--trace=AC_LIBLTDL_INSTALLABLE" (--trace=AC_LIBLTDL_INSTALLABLE) a21="--trace=AC_LIBTOOL_COMPILER_OPTION" (--trace=AC_LIBTOOL_COMPILER_OPTION) a22="--trace=AC_LIBTOOL_CONFIG" (--trace=AC_LIBTOOL_CONFIG) a23="--trace=AC_LIBTOOL_CXX" (--trace=AC_LIBTOOL_CXX) a24="--trace=AC_LIBTOOL_DLOPEN" (--trace=AC_LIBTOOL_DLOPEN) a25="--trace=AC_LIBTOOL_DLOPEN_SELF" (--trace=AC_LIBTOOL_DLOPEN_SELF) a26="--trace=AC_LIBTOOL_F77" (--trace=AC_LIBTOOL_F77) a27="--trace=AC_LIBTOOL_FC" (--trace=AC_LIBTOOL_FC) a28="--trace=AC_LIBTOOL_GCJ" (--trace=AC_LIBTOOL_GCJ) a29="--trace=AC_LIBTOOL_LANG_CXX_CONFIG" (--trace=AC_LIBTOOL_LANG_CXX_CONFIG) a30="--trace=AC_LIBTOOL_LANG_C_CONFIG" (--trace=AC_LIBTOOL_LANG_C_CONFIG) a31="--trace=AC_LIBTOOL_LANG_F77_CONFIG" (--trace=AC_LIBTOOL_LANG_F77_CONFIG) a32="--trace=AC_LIBTOOL_LANG_GCJ_CONFIG" (--trace=AC_LIBTOOL_LANG_GCJ_CONFIG) a33="--trace=AC_LIBTOOL_LANG_RC_CONFIG" (--trace=AC_LIBTOOL_LANG_RC_CONFIG) a34="--trace=AC_LIBTOOL_LINKER_OPTION" (--trace=AC_LIBTOOL_LINKER_OPTION) a35="--trace=AC_LIBTOOL_OBJDIR" (--trace=AC_LIBTOOL_OBJDIR) a36="--trace=AC_LIBTOOL_PICMODE" (--trace=AC_LIBTOOL_PICMODE) a37="--trace=AC_LIBTOOL_POSTDEP_PREDEP" (--trace=AC_LIBTOOL_POSTDEP_PREDEP) a38="--trace=AC_LIBTOOL_PROG_CC_C_O" (--trace=AC_LIBTOOL_PROG_CC_C_O) a39="--trace=AC_LIBTOOL_PROG_COMPILER_NO_RTTI" (--trace=AC_LIBTOOL_PROG_COMPILER_NO_RTTI) a40="--trace=AC_LIBTOOL_PROG_COMPILER_PIC" (--trace=AC_LIBTOOL_PROG_COMPILER_PIC) a41="--trace=AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH" (--trace=AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH) a42="--trace=AC_LIBTOOL_PROG_LD_SHLIBS" (--trace=AC_LIBTOOL_PROG_LD_SHLIBS) a43="--trace=AC_LIBTOOL_RC" (--trace=AC_LIBTOOL_RC) a44="--trace=AC_LIBTOOL_SETUP" (--trace=AC_LIBTOOL_SETUP) a45="--trace=AC_LIBTOOL_SYS_DYNAMIC_LINKER" (--trace=AC_LIBTOOL_SYS_DYNAMIC_LINKER) a46="--trace=AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE" (--trace=AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE) a47="--trace=AC_LIBTOOL_SYS_HARD_LINK_LOCKS" (--trace=AC_LIBTOOL_SYS_HARD_LINK_LOCKS) a48="--trace=AC_LIBTOOL_SYS_LIB_STRIP" (--trace=AC_LIBTOOL_SYS_LIB_STRIP) a49="--trace=AC_LIBTOOL_SYS_MAX_CMD_LEN" (--trace=AC_LIBTOOL_SYS_MAX_CMD_LEN) a50="--trace=AC_LIBTOOL_SYS_OLD_ARCHIVE" (--trace=AC_LIBTOOL_SYS_OLD_ARCHIVE) a51="--trace=AC_LIBTOOL_WIN32_DLL" (--trace=AC_LIBTOOL_WIN32_DLL) a52="--trace=AC_LIB_LTDL" (--trace=AC_LIB_LTDL) a53="--trace=AC_LTDL_DLLIB" (--trace=AC_LTDL_DLLIB) a54="--trace=AC_LTDL_DLSYM_USCORE" (--trace=AC_LTDL_DLSYM_USCORE) a55="--trace=AC_LTDL_ENABLE_INSTALL" (--trace=AC_LTDL_ENABLE_INSTALL) a56="--trace=AC_LTDL_OBJDIR" (--trace=AC_LTDL_OBJDIR) a57="--trace=AC_LTDL_PREOPEN" (--trace=AC_LTDL_PREOPEN) a58="--trace=AC_LTDL_SHLIBEXT" (--trace=AC_LTDL_SHLIBEXT) a59="--trace=AC_LTDL_SHLIBPATH" (--trace=AC_LTDL_SHLIBPATH) a60="--trace=AC_LTDL_SYMBOL_USCORE" (--trace=AC_LTDL_SYMBOL_USCORE) a61="--trace=AC_LTDL_SYSSEARCHPATH" (--trace=AC_LTDL_SYSSEARCHPATH) a62="--trace=AC_LTDL_SYS_DLOPEN_DEPLIBS" (--trace=AC_LTDL_SYS_DLOPEN_DEPLIBS) a63="--trace=AC_PATH_MAGIC" (--trace=AC_PATH_MAGIC) a64="--trace=AC_PATH_TOOL_PREFIX" (--trace=AC_PATH_TOOL_PREFIX) a65="--trace=AC_PROG_EGREP" (--trace=AC_PROG_EGREP) a66="--trace=AC_PROG_LD" (--trace=AC_PROG_LD) a67="--trace=AC_PROG_LD_GNU" (--trace=AC_PROG_LD_GNU) a68="--trace=AC_PROG_LD_RELOAD_FLAG" (--trace=AC_PROG_LD_RELOAD_FLAG) a69="--trace=AC_PROG_LIBTOOL" (--trace=AC_PROG_LIBTOOL) a70="--trace=AC_PROG_NM" (--trace=AC_PROG_NM) a71="--trace=AC_WITH_LTDL" (--trace=AC_WITH_LTDL) a72="--trace=AM_AUTOMAKE_VERSION" (--trace=AM_AUTOMAKE_VERSION) a73="--trace=AM_AUX_DIR_EXPAND" (--trace=AM_AUX_DIR_EXPAND) a74="--trace=AM_CONDITIONAL" (--trace=AM_CONDITIONAL) a75="--trace=AM_DEP_TRACK" (--trace=AM_DEP_TRACK) a76="--trace=AM_DISABLE_SHARED" (--trace=AM_DISABLE_SHARED) a77="--trace=AM_DISABLE_STATIC" (--trace=AM_DISABLE_STATIC) a78="--trace=AM_ENABLE_SHARED" (--trace=AM_ENABLE_SHARED) a79="--trace=AM_ENABLE_STATIC" (--trace=AM_ENABLE_STATIC) a80="--trace=AM_INIT_AUTOMAKE" (--trace=AM_INIT_AUTOMAKE) a81="--trace=AM_MAKE_INCLUDE" (--trace=AM_MAKE_INCLUDE) a82="--trace=AM_MISSING_HAS_RUN" (--trace=AM_MISSING_HAS_RUN) a83="--trace=AM_MISSING_PROG" (--trace=AM_MISSING_PROG) a84="--trace=AM_OUTPUT_DEPENDENCY_COMMANDS" (--trace=AM_OUTPUT_DEPENDENCY_COMMANDS) a85="--trace=AM_PROG_CC_C_O" (--trace=AM_PROG_CC_C_O) a86="--trace=AM_PROG_INSTALL_SH" (--trace=AM_PROG_INSTALL_SH) a87="--trace=AM_PROG_INSTALL_STRIP" (--trace=AM_PROG_INSTALL_STRIP) a88="--trace=AM_PROG_LD" (--trace=AM_PROG_LD) a89="--trace=AM_PROG_LIBTOOL" (--trace=AM_PROG_LIBTOOL) a90="--trace=AM_PROG_NM" (--trace=AM_PROG_NM) a91="--trace=AM_RUN_LOG" (--trace=AM_RUN_LOG) a92="--trace=AM_SANITY_CHECK" (--trace=AM_SANITY_CHECK) a93="--trace=AM_SET_CURRENT_AUTOMAKE_VERSION" (--trace=AM_SET_CURRENT_AUTOMAKE_VERSION) a94="--trace=AM_SET_DEPDIR" (--trace=AM_SET_DEPDIR) a95="--trace=AM_SET_LEADING_DOT" (--trace=AM_SET_LEADING_DOT) a96="--trace=AM_SILENT_RULES" (--trace=AM_SILENT_RULES) a97="--trace=AM_SUBST_NOTMAKE" (--trace=AM_SUBST_NOTMAKE) a98="--trace=AU_DEFUN" (--trace=AU_DEFUN) a99="--trace=LTDL_CONVENIENCE" (--trace=LTDL_CONVENIENCE) a100="--trace=LTDL_INIT" (--trace=LTDL_INIT) a101="--trace=LTDL_INSTALLABLE" (--trace=LTDL_INSTALLABLE) a102="--trace=LTOBSOLETE_VERSION" (--trace=LTOBSOLETE_VERSION) a103="--trace=LTOPTIONS_VERSION" (--trace=LTOPTIONS_VERSION) a104="--trace=LTSUGAR_VERSION" (--trace=LTSUGAR_VERSION) a105="--trace=LTVERSION_VERSION" (--trace=LTVERSION_VERSION) a106="--trace=LT_AC_PROG_EGREP" (--trace=LT_AC_PROG_EGREP) a107="--trace=LT_AC_PROG_GCJ" (--trace=LT_AC_PROG_GCJ) a108="--trace=LT_AC_PROG_RC" (--trace=LT_AC_PROG_RC) a109="--trace=LT_AC_PROG_SED" (--trace=LT_AC_PROG_SED) a110="--trace=LT_CMD_MAX_LEN" (--trace=LT_CMD_MAX_LEN) a111="--trace=LT_CONFIG_LTDL_DIR" (--trace=LT_CONFIG_LTDL_DIR) a112="--trace=LT_FUNC_ARGZ" (--trace=LT_FUNC_ARGZ) a113="--trace=LT_FUNC_DLSYM_USCORE" (--trace=LT_FUNC_DLSYM_USCORE) a114="--trace=LT_INIT" (--trace=LT_INIT) a115="--trace=LT_LANG" (--trace=LT_LANG) a116="--trace=LT_LIB_DLLOAD" (--trace=LT_LIB_DLLOAD) a117="--trace=LT_LIB_M" (--trace=LT_LIB_M) a118="--trace=LT_OUTPUT" (--trace=LT_OUTPUT) a119="--trace=LT_PATH_LD" (--trace=LT_PATH_LD) a120="--trace=LT_PATH_NM" (--trace=LT_PATH_NM) a121="--trace=LT_PROG_GCJ" (--trace=LT_PROG_GCJ) a122="--trace=LT_PROG_GO" (--trace=LT_PROG_GO) a123="--trace=LT_PROG_RC" (--trace=LT_PROG_RC) a124="--trace=LT_SUPPORTED_TAG" (--trace=LT_SUPPORTED_TAG) a125="--trace=LT_SYS_DLOPEN_DEPLIBS" (--trace=LT_SYS_DLOPEN_DEPLIBS) a126="--trace=LT_SYS_DLOPEN_SELF" (--trace=LT_SYS_DLOPEN_SELF) a127="--trace=LT_SYS_DLSEARCH_PATH" (--trace=LT_SYS_DLSEARCH_PATH) a128="--trace=LT_SYS_MODULE_EXT" (--trace=LT_SYS_MODULE_EXT) a129="--trace=LT_SYS_MODULE_PATH" (--trace=LT_SYS_MODULE_PATH) a130="--trace=LT_SYS_SYMBOL_USCORE" (--trace=LT_SYS_SYMBOL_USCORE) a131="--trace=LT_WITH_LTDL" (--trace=LT_WITH_LTDL) a132="--trace=_AC_AM_CONFIG_HEADER_HOOK" (--trace=_AC_AM_CONFIG_HEADER_HOOK) a133="--trace=_AC_PROG_LIBTOOL" (--trace=_AC_PROG_LIBTOOL) a134="--trace=_AM_AUTOCONF_VERSION" (--trace=_AM_AUTOCONF_VERSION) a135="--trace=_AM_CONFIG_MACRO_DIRS" (--trace=_AM_CONFIG_MACRO_DIRS) a136="--trace=_AM_DEPENDENCIES" (--trace=_AM_DEPENDENCIES) a137="--trace=_AM_IF_OPTION" (--trace=_AM_IF_OPTION) a138="--trace=_AM_MANGLE_OPTION" (--trace=_AM_MANGLE_OPTION) a139="--trace=_AM_OUTPUT_DEPENDENCY_COMMANDS" (--trace=_AM_OUTPUT_DEPENDENCY_COMMANDS) a140="--trace=_AM_PROG_CC_C_O" (--trace=_AM_PROG_CC_C_O) a141="--trace=_AM_PROG_TAR" (--trace=_AM_PROG_TAR) a142="--trace=_AM_SET_OPTION" (--trace=_AM_SET_OPTION) a143="--trace=_AM_SET_OPTIONS" (--trace=_AM_SET_OPTIONS) a144="--trace=_AM_SUBST_NOTMAKE" (--trace=_AM_SUBST_NOTMAKE) a145="--trace=_LTDL_SETUP" (--trace=_LTDL_SETUP) a146="--trace=_LT_AC_CHECK_DLFCN" (--trace=_LT_AC_CHECK_DLFCN) a147="--trace=_LT_AC_FILE_LTDLL_C" (--trace=_LT_AC_FILE_LTDLL_C) a148="--trace=_LT_AC_LANG_CXX" (--trace=_LT_AC_LANG_CXX) a149="--trace=_LT_AC_LANG_CXX_CONFIG" (--trace=_LT_AC_LANG_CXX_CONFIG) a150="--trace=_LT_AC_LANG_C_CONFIG" (--trace=_LT_AC_LANG_C_CONFIG) a151="--trace=_LT_AC_LANG_F77" (--trace=_LT_AC_LANG_F77) a152="--trace=_LT_AC_LANG_F77_CONFIG" (--trace=_LT_AC_LANG_F77_CONFIG) a153="--trace=_LT_AC_LANG_GCJ" (--trace=_LT_AC_LANG_GCJ) a154="--trace=_LT_AC_LANG_GCJ_CONFIG" (--trace=_LT_AC_LANG_GCJ_CONFIG) a155="--trace=_LT_AC_LANG_RC_CONFIG" (--trace=_LT_AC_LANG_RC_CONFIG) a156="--trace=_LT_AC_LOCK" (--trace=_LT_AC_LOCK) a157="--trace=_LT_AC_PROG_CXXCPP" (--trace=_LT_AC_PROG_CXXCPP) a158="--trace=_LT_AC_PROG_ECHO_BACKSLASH" (--trace=_LT_AC_PROG_ECHO_BACKSLASH) a159="--trace=_LT_AC_SHELL_INIT" (--trace=_LT_AC_SHELL_INIT) a160="--trace=_LT_AC_SYS_COMPILER" (--trace=_LT_AC_SYS_COMPILER) a161="--trace=_LT_AC_SYS_LIBPATH_AIX" (--trace=_LT_AC_SYS_LIBPATH_AIX) a162="--trace=_LT_AC_TAGCONFIG" (--trace=_LT_AC_TAGCONFIG) a163="--trace=_LT_AC_TAGVAR" (--trace=_LT_AC_TAGVAR) a164="--trace=_LT_AC_TRY_DLOPEN_SELF" (--trace=_LT_AC_TRY_DLOPEN_SELF) a165="--trace=_LT_CC_BASENAME" (--trace=_LT_CC_BASENAME) a166="--trace=_LT_COMPILER_BOILERPLATE" (--trace=_LT_COMPILER_BOILERPLATE) a167="--trace=_LT_COMPILER_OPTION" (--trace=_LT_COMPILER_OPTION) a168="--trace=_LT_DLL_DEF_P" (--trace=_LT_DLL_DEF_P) a169="--trace=_LT_LIBOBJ" (--trace=_LT_LIBOBJ) a170="--trace=_LT_LINKER_BOILERPLATE" (--trace=_LT_LINKER_BOILERPLATE) a171="--trace=_LT_LINKER_OPTION" (--trace=_LT_LINKER_OPTION) a172="--trace=_LT_PATH_TOOL_PREFIX" (--trace=_LT_PATH_TOOL_PREFIX) a173="--trace=_LT_PREPARE_SED_QUOTE_VARS" (--trace=_LT_PREPARE_SED_QUOTE_VARS) a174="--trace=_LT_PROG_CXX" (--trace=_LT_PROG_CXX) a175="--trace=_LT_PROG_ECHO_BACKSLASH" (--trace=_LT_PROG_ECHO_BACKSLASH) a176="--trace=_LT_PROG_F77" (--trace=_LT_PROG_F77) a177="--trace=_LT_PROG_FC" (--trace=_LT_PROG_FC) a178="--trace=_LT_PROG_LTMAIN" (--trace=_LT_PROG_LTMAIN) a179="--trace=_LT_REQUIRED_DARWIN_CHECKS" (--trace=_LT_REQUIRED_DARWIN_CHECKS) a180="--trace=_LT_WITH_SYSROOT" (--trace=_LT_WITH_SYSROOT) a181="--trace=_m4_warn" (--trace=_m4_warn) a182="--trace=include" (--trace=include) a183="--trace=m4_include" (--trace=m4_include) a184="--trace=m4_pattern_allow" (--trace=m4_pattern_allow) a185="--trace=m4_pattern_forbid" (--trace=m4_pattern_forbid) a186="--reload-state=/usr/share/autoconf-2.60/autoconf/autoconf.m4f" (--reload-state=/usr/share/autoconf-2.60/autoconf/autoconf.m4f) a187="--undefine=__m4_version__" (--undefine=__m4_version__) a188="-" (-) a189="/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4" (/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4) a190="/usr/share/libtool/aclocal/libtool.m4" (/usr/share/libtool/aclocal/libtool.m4) a191="/usr/share/libtool/aclocal/ltargz.m4" (/usr/share/libtool/aclocal/ltargz.m4) a192="/usr/share/libtool/aclocal/ltdl.m4" (/usr/share/libtool/aclocal/ltdl.m4) a193="/usr/share/libtool/aclocal/ltoptions.m4" (/usr/share/libtool/aclocal/ltoptions.m4) a194="/usr/share/libtool/aclocal/ltsugar.m4" (/usr/share/libtool/aclocal/ltsugar.m4) a195="/usr/share/libtool/aclocal/ltversion.m4" (/usr/share/libtool/aclocal/ltversion.m4) a196="/usr/share/libtool/aclocal/lt~obsolete.m4" (/usr/share/libtool/aclocal/lt~obsolete.m4) a197="/usr/share/aclocal-1.16/amversion.m4" (/usr/share/aclocal-1.16/amversion.m4) a198="/usr/share/aclocal-1.16/auxdir.m4" (/usr/share/aclocal-1.16/auxdir.m4) a199="/usr/share/aclocal-1.16/cond.m4" (/usr/share/aclocal-1.16/cond.m4) a200="/usr/share/aclocal-1.16/depend.m4" (/usr/share/aclocal-1.16/depend.m4) a201="/usr/share/aclocal-1.16/depout.m4" (/usr/share/aclocal-1.16/depout.m4) a202="/usr/share/aclocal-1.16/init.m4" (/usr/share/aclocal-1.16/init.m4) a203="/usr/share/aclocal-1.16/install-sh.m4" (/usr/share/aclocal-1.16/install-sh.m4) a204="/usr/share/aclocal-1.16/lead-dot.m4" (/usr/share/aclocal-1.16/lead-dot.m4) a205="/usr/share/aclocal-1.16/make.m4" (/usr/share/aclocal-1.16/make.m4) a206="/usr/share/aclocal-1.16/missing.m4" (/usr/share/aclocal-1.16/missing.m4) a207="/usr/share/aclocal-1.16/options.m4" (/usr/share/aclocal-1.16/options.m4) a208="/usr/share/aclocal-1.16/prog-cc-c-o.m4" (/usr/share/aclocal-1.16/prog-cc-c-o.m4) a209="/usr/share/aclocal-1.16/runlog.m4" (/usr/share/aclocal-1.16/runlog.m4) a210="/usr/share/aclocal-1.16/sanity.m4" (/usr/share/aclocal-1.16/sanity.m4) a211="/usr/share/aclocal-1.16/silent.m4" (/usr/share/aclocal-1.16/silent.m4) a212="/usr/share/aclocal-1.16/strip.m4" (/usr/share/aclocal-1.16/strip.m4) a213="/usr/share/aclocal-1.16/substnot.m4" (/usr/share/aclocal-1.16/substnot.m4) a214="/usr/share/aclocal-1.16/tar.m4" (/usr/share/aclocal-1.16/tar.m4) a215="configure.ac" (configure.ac) record 3 of type 1307(CWD) has 2 fields line=10 file=test4.log event time: 1655465404.819:27091, host=(null) type=CWD (CWD) cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1/contrib/minizip" (/usr/src/RPM/BUILD/zlib-1.2.11-alt1/contrib/minizip) record 4 of type 1302(PATH) has 15 fields line=11 file=test4.log event time: 1655465404.819:27091, host=(null) type=PATH (PATH) item=0 (0) name="/usr/bin/m4" (/usr/bin/m4) inode=40839 (40839) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 5 of type 1302(PATH) has 15 fields line=12 file=test4.log event time: 1655465404.819:27091, host=(null) type=PATH (PATH) item=1 (1) name="/lib64/ld-linux-aarch64.so.1" (/lib64/ld-linux-aarch64.so.1) inode=33874 (33874) dev=00:30 (00:30) mode=0100755 (file,755) ouid=582 (unknown(582)) ogid=582 (unknown(582)) rdev=00:00 (00:00) nametype=NORMAL (NORMAL) cap_fp=0 (none) cap_fi=0 (none) cap_fe=0 (0) cap_fver=0 (0) cap_frootid=0 (0) record 6 of type 1327(PROCTITLE) has 2 fields line=13 file=test4.log event time: 1655465404.819:27091, host=(null) type=PROCTITLE (PROCTITLE) proctitle=2F7573722F62696E2F6D34002D2D6E657374696E672D6C696D69743D31303234002D2D676E75002D2D696E636C7564653D2F7573722F73686172652F6175746F636F6E662D322E3630002D2D64656275673D61666C71002D2D666174616C2D7761726E696E67002D2D646562756766696C653D6175746F6D3474652E63616368 (/usr/bin/m4 --nesting-limit=1024 --gnu --include=/usr/share/autoconf-2.60 --debug=aflq --fatal-warning --debugfile=autom4te.cach) Test 11 Done Finished non-admin tests audit-userspace-4.0.5/auparse/test/auparselol_test.c000066400000000000000000000170601501761310600226130ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include #include #include "libaudit.h" #include "auparse.h" /* * Tool to exercise the auparse library input and processing capability * Based on the code example shown in auparse_feed manual entry * * Standard test would be * mkdir /tmp/auparse_test * cp /var/log/audit/audit.log /tmp/auparse_test/audit.log * sed -f auparse_patch.sed /tmp/auparse_test/audit.log | sort > /tmp/auparse_test/auparse.raw * auparselol_test --check -f /tmp/auparse_test/audit.log | sort > /tmp/auparse_test/auparse.new * diff /tmp/auparse_test/auparse.raw /tmp/auparse_test/auparse.new * and the output of the diff should be zero or explainable (and hence expand the auparse_patch.sed file) * */ /* * Flags bitset */ unsigned flags = 0x0; #define F_VERBOSE 0x00000001 #define F_CHECK 0x00000002 #define F_USESTDIN 0x00000004 /* * Print a null terminated string, escaping chararters from the given set */ void print_escape(FILE * fd, char *str, const char *escape) { register char *s = str; int ch; while ((ch = (int) *s++)) { if (strrchr(escape, ch)) fputc('\\', fd); fputc(ch, fd); } } /* * auparse_callback - callback routine to be executed once a complete event is composed */ void auparse_callback(auparse_state_t * au, auparse_cb_event_t cb_event_type, void *user_data) { int *event_cnt = (int *) user_data; if (cb_event_type == AUPARSE_CB_EVENT_READY) { if (auparse_first_record(au) <= 0) return; /* If no first record, then no event ! */ if (!(flags & F_CHECK)) printf("event=%d records=%u\n", *event_cnt, auparse_get_num_records(au)); do { const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) return; /* If no timestamp, then no event */ /* If checking, we just emit the raw record again */ if (flags & F_CHECK) { if (e->host != NULL) printf("node=%s type=%s msg=audit(%u.%3.3u:%lu):", e->host, auparse_get_type_name(au), (unsigned) e->sec, e->milli, e->serial); else printf("type=%s msg=audit(%u.%3.3u:%lu):", auparse_get_type_name(au), (unsigned) e->sec, e->milli, e->serial); auparse_first_field(au); /* Move to first field */ do { const char *fname = auparse_get_field_name(au); /* We ignore the node and type fields */ if (strcmp(fname, "type") == 0 || strcmp(fname, "node") == 0) continue; printf(" %s=%s", fname, auparse_get_field_str(au)); } while (auparse_next_field(au) > 0); printf("\n"); continue; } printf("fields=%u\t", auparse_get_num_fields(au)); printf("type=%d (%s) ", auparse_get_type(au), auparse_get_type_name(au)); printf("event_tid=%u.%3.3u:%lu ", (unsigned) e->sec, e->milli, e->serial); if (flags & F_VERBOSE) { char *fv, *ifv = NULL; auparse_first_field(au); /* Move to first field */ do { fv = (char *) auparse_get_field_str(au); ifv = (char *) auparse_interpret_field(au); printf("%s=", auparse_get_field_name(au)); print_escape(stdout, fv, "=()"); printf(" ("); print_escape(stdout, ifv, "=()"); printf(") "); } while (auparse_next_field(au) > 0); } printf("\n"); } while (auparse_next_record(au) > 0); (*event_cnt)++; } } void usage(void) { fprintf(stderr, "usage: auparselol_test [--stdin] [-f file] [--verbose] [--check] [--escape R|T|S|Q]\n"); } int main(int argc, char **argv) { char *filename = NULL; auparse_esc_t em; FILE *fd; #define BUFSZ 2048 char buf[BUFSZ]; size_t len; int *event_cnt = NULL; auparse_state_t *au; int i; /* Argument parsing */ while (1) { int option_index = 0; int c; static struct option long_options[] = { { "verbose", no_argument, 0, 'v'}, { "file", required_argument, 0, 'f'}, { "stdin", no_argument, 0, 's'}, { "check", no_argument, 0, 'c'}, { "escape", required_argument, 0, 'e'}, { 0, 0, 0, 0} }; c = getopt_long(argc, argv, "cvf:e:s", long_options, &option_index); if (c == -1) break; switch (c) { case 'e': /* escape mode */ switch (*optarg) { case 'R': case 'r': em = AUPARSE_ESC_RAW; break; case 'T': case 't': em = AUPARSE_ESC_TTY; break; case 'S': case 's': em = AUPARSE_ESC_SHELL; break; case 'Q': case 'q': em = AUPARSE_ESC_SHELL_QUOTE; break; default: fprintf(stderr, "%s: Unknown escape character 0x%2.2X\n", argv[0], *optarg); usage(); return 1; } auparse_set_escape_mode(NULL, em); break; case 'c': /* check */ flags |= F_CHECK; break; case 'v': /* verbose */ flags |= F_VERBOSE; break; case 's': /* stdin */ flags |= F_USESTDIN; break; case 'f': /* file */ filename = optarg; break; case '?': default: fprintf(stderr, "%s: Unknown option 0x%2.2X\n", argv[0], c); usage(); return 1; } } if ((flags & F_USESTDIN) && filename != NULL) { fprintf(stderr, "%s: --stdin cannot be used with file argument\n", argv[0]); usage(); return 1; } if (!(flags & F_USESTDIN) && filename == NULL) { fprintf(stderr, "%s: Missing --stdin or -f file argument\n", argv[0]); usage(); return 1; } if ((event_cnt = malloc(sizeof(int))) == NULL) { fprintf(stderr, "%s: No memory to allocate %lu bytes\n", argv[0], sizeof(int)); return 1; } if (flags & F_USESTDIN) { fd = stdin; } else { if ((fd = fopen(filename, "r")) == NULL) { fprintf(stderr, "could not open ’%s’, %s\n", filename, strerror(errno)); (void) free(event_cnt); return 1; } } au = auparse_init(AUSOURCE_FEED, NULL); *event_cnt = 1; auparse_add_callback(au, auparse_callback, event_cnt, free); i = 0; while ((len = fread(buf, 1, sizeof(buf), fd))) { auparse_feed(au, buf, len); i++; } auparse_flush_feed(au); auparse_destroy(au); /* this also free's event_cnt */ if (!(flags & F_USESTDIN)) fclose(fd); return 0; } audit-userspace-4.0.5/auparse/test/lookup_test.c000066400000000000000000000265251501761310600217630ustar00rootroot00000000000000/* lookup_test.c -- A test of table lookups. * Copyright 2017 Red Hat Inc. * All Rights Reserved. * * 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 program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include "gen_tables.h" // To see if new tests are needed: // $ grep 'i2s(int v)' ../*.h | wc -l // 30 // only headers with i2s can be tested. /* Number of lookups of random strings */ #define RAND_ITERATIONS 1000 /* Maximum size of randomly generated strings, including the terminating NUL. */ #define S_LEN 8 struct entry { int val; const char *s; }; #define _S(V, S) { (V), (S) }, /* Generate a random string into DEST[S_LEN]. */ static void gen_id(char *dest) { size_t i, len; assert(S_LEN >= 2); len = 1 + rand() % (S_LEN - 1); assert('A' == 0x41 && 'a' == 0x61); /* ASCII */ for (i = 0; i < len; i++) { /* Don't start with a digit, audit_name_to_msg_type() interprets those strings specially. */ do { dest[i] = 0x21 + rand() % (0x7F - 0x21); } while (i == 0 && dest[i] >= '0' && dest[i] <= '9'); } dest[i] = '\0'; } static int debug = 0; #define TEST_I2S(EXCL) \ do { \ size_t i; \ \ for (i = 0; i < sizeof(t) / sizeof(*t); i++) { \ const char *s; \ \ if (EXCL) \ continue; \ s = I2S(t[i].val); \ if (s == NULL) { \ fprintf(stderr, \ "%d -> `%s' not found\n", \ t[i].val, t[i].s); \ abort(); \ } \ if (strcmp(t[i].s, s) != 0) { \ fprintf(stderr, \ "%d -> `%s' mismatch `%s'\n", \ t[i].val, t[i].s, s); \ abort(); \ } \ if (debug) printf("%d=%s\n", t[i].val, t[i].s); \ } \ for (i = 0; i < RAND_ITERATIONS; i++) { \ int val; \ size_t j; \ val = rand(); \ for (j = 0; j < sizeof(t) / sizeof(*t); j++) { \ if (t[j].val == val) \ goto test_i2s_found; \ } \ assert(I2S(val) == NULL); \ test_i2s_found: \ ; \ } \ } while (0) #define TEST_S2I(ERR_VALUE) \ do { \ size_t i; \ char buf[S_LEN]; \ \ for (i = 0; i < sizeof(t) / sizeof(*t); i++) \ assert(S2I(t[i].s) == t[i].val); \ for (i = 0; i < RAND_ITERATIONS; i++) { \ /* Blindly assuming this will not generate a \ meaningful identifier. */ \ gen_id(buf); \ if (S2I(buf) != (ERR_VALUE)) { \ fprintf(stderr, \ "Unexpected match `%s'\n", \ buf); \ abort(); \ } \ } \ } while (0) #include "../captabs.h" static void test_captab(void) { static const struct entry t[] = { #include "../captab.h" }; printf("Testing captab...\n"); #define I2S(I) cap_i2s(I) TEST_I2S(0); #undef I2S } #include "../clocktabs.h" static void test_clocktab(void) { static const struct entry t[] = { #include "../clocktab.h" }; printf("Testing clocktab...\n"); #define I2S(I) clock_i2s(I) TEST_I2S(0); #undef I2S } #include "../epoll_ctls.h" static void test_epoll_ctl(void) { static const struct entry t[] = { #include "../epoll_ctl.h" }; printf("Testing epoll_ctl...\n"); #define I2S(I) epoll_ctl_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../famtabs.h" static void test_famtab(void) { static const struct entry t[] = { #include "../famtab.h" }; printf("Testing famtab...\n"); #define I2S(I) fam_i2s(I) TEST_I2S(0); #undef I2S } #include "../fcntl-cmdtabs.h" static void test_fcntltab(void) { static const struct entry t[] = { #include "../fcntl-cmdtab.h" }; printf("Testing fcntltab...\n"); #define I2S(I) fcntl_i2s(I) TEST_I2S(0); #undef I2S } #include "../fsconfigs.h" static void test_fsconfig(void) { static const struct entry t[] = { #include "../fsconfig.h" }; printf("Testing fsconfig...\n"); #define I2S(I) fsconfig_i2s(I) TEST_I2S(0); #undef I2S } #include "../icmptypetabs.h" static void test_icmptypetab(void) { static const struct entry t[] = { #include "../icmptypetab.h" }; printf("Testing icmptypetab...\n"); #define I2S(I) icmptype_i2s(I) TEST_I2S(0); #undef I2S } #include "../inethooktabs.h" static void test_inethooktab(void) { static const struct entry t[] = { #include "../inethooktab.h" }; printf("Testing inethooktab...\n"); #define I2S(I) inethook_i2s(I) TEST_I2S(0); #undef I2S } #include "../ioctlreqtabs.h" static void test_ioctlreqtab(void) { static const struct entry t[] = { #include "../ioctlreqtab.h" }; printf("Testing ioctlreqtab...\n"); #define I2S(I) ioctlreq_i2s(I) TEST_I2S(0); #undef I2S } #include "../ip6optnametabs.h" static void test_ip6optnametab(void) { static const struct entry t[] = { #include "../ip6optnametab.h" }; printf("Testing ip6optnametab...\n"); #define I2S(I) ip6optname_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../ipctabs.h" static void test_ipctab(void) { static const struct entry t[] = { #include "../ipctab.h" }; printf("Testing ipctab...\n"); #define I2S(I) ipc_i2s(I) TEST_I2S(0); #undef I2S } #include "../ipoptnametabs.h" static void test_ipoptnametab(void) { static const struct entry t[] = { #include "../ipoptnametab.h" }; printf("Testing ipoptnametab...\n"); #define I2S(I) ipoptname_i2s(I) TEST_I2S(0); #undef I2S } #include "../netactiontabs.h" static void test_netactiontab(void) { static const struct entry t[] = { #include "../netactiontab.h" }; printf("Testing netactiontab...\n"); #define I2S(I) netaction_i2s(I) TEST_I2S(0); #undef I2S } #include "../nfprototabs.h" static void test_nfprototab(void) { static const struct entry t[] = { #include "../nfprototab.h" }; printf("Testing nfprototab...\n"); #define I2S(I) nfproto_i2s(I) TEST_I2S(0); #undef I2S } #include "../normalize_evtypetabs.h" static void test_evtypetab(void) { static const struct entry t[] = { #include "../normalize_evtypetab.h" }; printf("Testing evtypetab...\n"); #define I2S(I) evtype_i2s(I) TEST_I2S(0); #undef I2S } #include "../normalize_obj_kind_maps.h" static void test_normalize_obj_kind_map(void) { static const struct entry t[] = { #include "../normalize_obj_kind_map.h" }; printf("Testing normalize_obj_kind_map...\n"); #define I2S(I) normalize_obj_kind_map_i2s(I) TEST_I2S(0); #undef I2S } #include "libaudit.h" #include "../normalize_record_maps.h" static void test_normalize_record_map(void) { static const struct entry t[] = { #include "../normalize_record_map.h" }; printf("Testing normalize_record_map...\n"); #define I2S(I) normalize_record_map_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../persontabs.h" static void test_persontab(void) { static const struct entry t[] = { #include "../persontab.h" }; printf("Testing persontab...\n"); #define I2S(I) person_i2s(I) TEST_I2S(0); #undef I2S } #include "../pktoptnametabs.h" static void test_pktoptnametab(void) { static const struct entry t[] = { #include "../pktoptnametab.h" }; printf("Testing pktoptnametab...\n"); #define I2S(I) pktoptname_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../prctl_opttabs.h" static void test_prctl_opttab(void) { static const struct entry t[] = { #include "../prctl-opt-tab.h" }; printf("Testing prctl_opttab...\n"); #define I2S(I) prctl_opt_i2s(I) TEST_I2S(0); #undef I2S } #include "../ptracetabs.h" static void test_ptracetab(void) { static const struct entry t[] = { #include "../ptracetab.h" }; printf("Testing ptracetab...\n"); #define I2S(I) ptrace_i2s(I) TEST_I2S(0); #undef I2S } #include "../rlimittabs.h" static void test_rlimittab(void) { static const struct entry t[] = { #include "../rlimittab.h" }; printf("Testing rlimittab...\n"); #define I2S(I) rlimit_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../schedtabs.h" static void test_schedtab(void) { static const struct entry t[] = { #include "../schedtab.h" }; printf("Testing schedtab...\n"); #define I2S(I) sched_i2s(I) TEST_I2S(0); #undef I2S } #include "../seccomptabs.h" static void test_seccomptab(void) { static const struct entry t[] = { #include "../seccomptab.h" }; printf("Testing seccomptab...\n"); #define I2S(I) seccomp_i2s(I) TEST_I2S(0); #undef I2S } #include "../seektabs.h" static void test_seektab(void) { static const struct entry t[] = { #include "../seektab.h" }; printf("Testing seektab...\n"); #define I2S(I) seek_i2s(I) TEST_I2S(0); #undef I2S } #include "../signaltabs.h" static void test_signaltab(void) { static const struct entry t[] = { #include "../signaltab.h" }; printf("Testing signaltab...\n"); #define I2S(I) signal_i2s(I) TEST_I2S(0); #undef I2S } #include "../sockleveltabs.h" static void test_sockleveltab(void) { static const struct entry t[] = { #include "../sockleveltab.h" }; printf("Testing sockleveltab...\n"); #define I2S(I) socklevel_i2s(I) TEST_I2S(0); #undef I2S } #include "../sockoptnametabs.h" static void test_sockoptnametab(void) { static const struct entry t[] = { #include "../sockoptnametab.h" }; printf("Testing sockoptnametab...\n"); #define I2S(I) sockoptname_i2s(I) TEST_I2S(0); #undef I2S } #include #include "../socktabs.h" static void test_socktab(void) { static const struct entry t[] = { #include "../socktab.h" }; printf("Testing socktab...\n"); #define I2S(I) sock_i2s(I) TEST_I2S(0); #undef I2S } #include "../socktypetabs.h" static void test_socktypetab(void) { static const struct entry t[] = { #include "../socktypetab.h" }; printf("Testing socktypetab...\n"); #define I2S(I) sock_type_i2s(I) TEST_I2S(0); #undef I2S } #include "../tcpoptnametabs.h" static void test_tcpoptnametab(void) { static const struct entry t[] = { #include "../tcpoptnametab.h" }; printf("Testing tcpoptnametab...\n"); #define I2S(I) tcpoptname_i2s(I) TEST_I2S(0); #undef I2S } int main(void) { // This is only for preventing collisions in s2i tests. // If collisions are found in future, change the number. srand(3); test_captab(); test_clocktab(); test_epoll_ctl(); test_famtab(); test_fcntltab(); test_fsconfig(); test_icmptypetab(); test_inethooktab(); test_ioctlreqtab(); test_ip6optnametab(); test_ipctab(); test_ipoptnametab(); test_netactiontab(); test_nfprototab(); test_evtypetab(); test_normalize_obj_kind_map(); test_normalize_record_map(); test_persontab(); test_pktoptnametab(); test_prctl_opttab(); test_ptracetab(); test_rlimittab(); test_schedtab(); test_seccomptab(); test_seektab(); test_signaltab(); test_sockleveltab(); test_sockoptnametab(); test_socktab(); test_socktypetab(); test_tcpoptnametab(); puts("==============================="); puts("Interpretation table tests pass"); puts("==============================="); return EXIT_SUCCESS; } audit-userspace-4.0.5/auparse/test/test.log000066400000000000000000000047411501761310600207250ustar00rootroot00000000000000type=AVC msg=audit(1170021493.977:293): avc: denied { read write } for pid=13010 comm="pickup" name="maildrop" dev=hda7 ino=14911367 scontext=system_u:system_r:postfix_pickup_t:s0 tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 tclass=dir type=SYSCALL msg=audit(1170021493.977:293): arch=c000003e syscall=2 success=no exit=-13 a0=5555665d91b0 a1=10800 a2=5555665d91b8 a3=0 items=1 ppid=2013 pid=13010 auid=4294967295 uid=890 gid=890 euid=890 suid=890 fsuid=890 egid=890 sgid=890 fsgid=890 tty=(none) comm="pickup" exe="/usr/libexec/postfix/pickup" subj=system_u:system_r:postfix_pickup_t:s0 key=(null) type=CWD msg=audit(1170021493.977:293): cwd="/var/spool/postfix" type=PATH msg=audit(1170021493.977:293): item=0 name="maildrop" inode=14911367 dev=03:07 mode=040730 ouid=890 ogid=891 rdev=00:00 obj=system_u:object_r:postfix_spool_maildrop_t:s0 type=USER_ACCT msg=audit(1170021601.340:294): user pid=13015 uid=0 auid=4294967295 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: accounting acct=root : exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success' type=CRED_ACQ msg=audit(1170021601.342:295): user pid=13015 uid=0 auid=4294967295 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: setcred acct=root : exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success' type=LOGIN msg=audit(1170021601.343:296): pid=2288 uid=0 subj=system_u:system_r:init_t:s0 old-auid=4294967295 auid=42 tty=(none) old-ses=4294967295 ses=1 res=1 type=SYSCALL msg=audit(1170021601.343:296): arch=c000003e syscall=1 success=yes exit=2 a0=8 a1=7fffa7aede20 a2=2 a3=0 items=0 ppid=1 pid=2288 auid=42 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="(systemd)" exe="/usr/lib/systemd/systemd" subj=system_u:system_r:init_t:s0 key=(null) type=PROCTITLE msg=audit(1170021601.343:296): proctitle="(systemd)" type=USER_START msg=audit(1170021601.344:297): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: session open acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' type=CRED_DISP msg=audit(1170021601.364:298): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: setcred acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' type=USER_END msg=audit(1170021601.366:299): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: session close acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' audit-userspace-4.0.5/auparse/test/test2.log000066400000000000000000000047331501761310600210100ustar00rootroot00000000000000type=AVC msg=audit(1170021493.977:283): avc: denied { read } for pid=13010 comm="pickup" name="maildrop" dev=hda7 ino=14911367 scontext=system_u:system_r:postfix_pickup_t:s0 tcontext=system_u:object_r:postfix_spool_maildrop_t:s0 tclass=dir type=SYSCALL msg=audit(1170021493.977:283): arch=c000003e syscall=2 success=no exit=-13 a0=5555665d91b0 a1=10800 a2=5555665d91b8 a3=0 items=1 ppid=2013 pid=13010 auid=4294967295 uid=890 gid=890 euid=890 suid=890 fsuid=890 egid=890 sgid=890 fsgid=890 tty=(none) comm="pickup" exe="/usr/libexec/postfix/pickup" subj=system_u:system_r:postfix_pickup_t:s0 key=(null) type=CWD msg=audit(1170021493.977:283): cwd="/var/spool/postfix" type=PATH msg=audit(1170021493.977:283): item=0 name="maildrop" inode=14911367 dev=03:07 mode=040730 ouid=890 ogid=891 rdev=00:00 obj=system_u:object_r:postfix_spool_maildrop_t:s0 type=USER_ACCT msg=audit(1170021601.340:284): user pid=13015 uid=0 auid=4294967295 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: accounting acct=root : exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success' type=CRED_ACQ msg=audit(1170021601.342:285): user pid=13015 uid=0 auid=4294967295 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: setcred acct=root : exe="/usr/sbin/crond" hostname=? addr=? terminal=cron res=success' type=LOGIN msg=audit(1170021601.343:286): pid=2288 uid=0 subj=system_u:system_r:init_t:s0 old-auid=4294967295 auid=42 tty=(none) old-ses=4294967295 ses=1 res=1 type=SYSCALL msg=audit(1170021601.343:286): arch=c000003e syscall=1 success=yes exit=2 a0=8 a1=7fffa7aede20 a2=2 a3=0 items=0 ppid=1 pid=2288 auid=42 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=1 comm="(systemd)" exe="/usr/lib/systemd/systemd" subj=system_u:system_r:init_t:s0 key=(null) type=PROCTITLE msg=audit(1170021601.343:286): proctitle="(systemd)" type=USER_START msg=audit(1170021601.344:287): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: session open acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' type=CRED_DISP msg=audit(1170021601.364:288): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: setcred acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' type=USER_END msg=audit(1170021601.366:289): user pid=13015 uid=0 auid=0 subj=system_u:system_r:crond_t:s0-s0:c0.c1023 msg='PAM: session close acct=root : exe="/usr/sbin/crond" (hostname=?, addr=?, terminal=cron res=success)' audit-userspace-4.0.5/auparse/test/test3.log000066400000000000000000000071271501761310600210110ustar00rootroot00000000000000node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194435): arch=c000003e syscall=23 success=yes exit=1 a0=c a1=56420184ade0 a2=564201867510 a3=0 items=0 ppid=1271 pid=1281 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=1 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194433): arch=c000003e syscall=13 success=yes exit=0 a0=b a1=7ffd42eb1590 a2=0 a3=8 items=0 ppid=1306 pid=1321 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194433): proctitle="bash" node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194435): proctitle=737368643A206275726E205B707269765D node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194436): arch=c000003e syscall=13 success=yes exit=0 a0=1f a1=7ffd42eb1590 a2=0 a3=8 items=0 ppid=1306 pid=1321 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194437): arch=c000003e syscall=14 success=yes exit=0 a0=0 a1=7ffdac6fe9a0 a2=7ffdac6fe920 a3=8 items=0 ppid=1271 pid=1281 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=1 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194436): proctitle="bash" node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194437): proctitle=737368643A206275726E205B707269765D node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194438): arch=c000003e syscall=13 success=yes exit=0 a0=d a1=7ffd42eb1590 a2=0 a3=8 items=0 ppid=1306 pid=1321 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194439): arch=c000003e syscall=14 success=yes exit=0 a0=2 a1=7ffdac6fe920 a2=0 a3=8 items=0 ppid=1271 pid=1281 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=1 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194439): proctitle=737368643A206275726E205B707269765D node=auditdtest.a1959.org type=SYSCALL msg=audit(1451781471.394:194440): arch=c000003e syscall=228 success=yes exit=0 a0=7 a1=7ffdac6fe9c0 a2=564201867510 a3=8 items=0 ppid=1271 pid=1281 auid=1000 uid=1000 gid=1000 euid=1000 suid=1000 fsuid=1000 egid=1000 sgid=1000 fsgid=1000 tty=(none) ses=1 comm="sshd" exe="/usr/sbin/sshd" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null) node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194438): proctitle="bash" node=auditdtest.a1959.org type=PROCTITLE msg=audit(1451781471.394:194440): proctitle=737368643A206275726E205B707269765D node=auditdtest.a1959.org type=ADD_GROUP msg=audit(1451781471.602:194894): pid=1321 uid=0 auid=1000 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 msg='op=add-group acct="frodo" exe="/usr/sbin/useradd" hostname=? addr=? terminal=pts/0 res=success' audit-userspace-4.0.5/auparse/test/test4.log000066400000000000000000000256641501761310600210200ustar00rootroot00000000000000type=SYSCALL msg=audit(1655465398.534:25618): arch=c000003e syscall=59 success=yes exit=0 a0=8c403a0 a1=8c3e8b0 a2=fffffb6cc5b0 a3=0 items=3 ppid=105182 pid=105183 auid=573 uid=583 gid=583 euid=583 suid=583 fsuid=583 egid=583 sgid=583 fsgid=583 tty=pts2 ses=2632 comm="ld" exe="/bin/sh4" key=(null) type=EXECVE msg=audit(1655465398.534:25618): argc=48 a0="/bin/sh" a1="-efu" a2="/usr/bin/ld" a3="-plugin" a4="/usr/libexec/gcc/aarch64-alt-linux/8/liblto_plugin.so" a5="-plugin-opt=/usr/libexec/gcc/aarch64-alt-linux/8/lto-wrapper" a6="-plugin-opt=-fresolution=/usr/src/tmp/cchyHiZN.res" a7="-plugin-opt=-pass-through=-lgcc" a8="-plugin-opt=-pass-through=-lgcc_s" a9="-plugin-opt=-pass-through=-lc" a10="-plugin-opt=-pass-through=-lgcc" a11="-plugin-opt=-pass-through=-lgcc_s" a12="--build-id" a13="--no-add-needed" a14="--eh-frame-hdr" a15="--hash-style=gnu" a16="--as-needed" a17="-shared" a18="-X" a19="-EL" a20="-maarch64linux" a21="-o" a22="ztest105133.so" a23="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crti.o" a24="/usr/lib64/gcc/aarch64-alt-linux/8/crtbeginS.o" a25="-L/usr/lib64/gcc/aarch64-alt-linux/8" a26="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64" a27="-L/lib/../lib64" a28="-L/usr/lib/../lib64" a29="-L/usr/lib64/gcc/aarch64-alt-linux/8/../../.." a30="-soname" a31="libz.so.1" a32="--version-script" a33="zlib.map" a34="ztest105133.o" a35="-lgcc" a36="--push-state" a37="--as-needed" a38="-lgcc_s" a39="--pop-state" a40="-lc" a41="-lgcc" a42="--push-state" a43="--as-needed" a44="-lgcc_s" a45="--pop-state" a46="/usr/lib64/gcc/aarch64-alt-linux/8/crtendS.o" a47="/usr/lib64/gcc/aarch64-alt-linux/8/../../../../lib64/crtn.o" type=CWD msg=audit(1655465398.534:25618): cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1" type=PATH msg=audit(1655465398.534:25618): item=0 name="/usr/bin/ld" inode=40854 dev=00:30 mode=0100755 ouid=582 ogid=582 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0 type=PATH msg=audit(1655465398.534:25618): item=1 name="/bin/sh" inode=33238 dev=00:30 mode=0100755 ouid=582 ogid=582 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0 type=PATH msg=audit(1655465398.534:25618): item=2 name="/lib64/ld-linux-aarch64.so.1" inode=33874 dev=00:30 mode=0100755 ouid=582 ogid=582 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0 type=PROCTITLE msg=audit(1655465398.534:25618): proctitle=2F62696E2F7368002D656675002F7573722F62696E2F6C64002D706C7567696E002F7573722F6C6962657865632F6763632F616172636836342D616C742D6C696E75782F382F6C69626C746F5F706C7567696E2E736F002D706C7567696E2D6F70743D2F7573722F6C6962657865632F6763632F616172636836342D616C742D type=SYSCALL msg=audit(1655465404.819:27091): arch=c000003e syscall=59 success=yes exit=0 a0=1a407f50 a1=1a401cd0 a2=1a3ed090 a3=0 items=2 ppid=105932 pid=105933 auid=573 uid=583 gid=583 euid=583 suid=583 fsuid=583 egid=583 sgid=583 fsgid=583 tty=pts2 ses=2632 comm="m4" exe="/usr/bin/m4" key=(null) type=EXECVE msg=audit(1655465404.819:27091): argc=216 a0="/usr/bin/m4" a1="--nesting-limit=1024" a2="--gnu" a3="--include=/usr/share/autoconf-2.60" a4="--debug=aflq" a5="--fatal-warning" a6="--debugfile=autom4te.cache/traces.0t" a7="--trace=AC_CHECK_LIBM" a8="--trace=AC_CONFIG_MACRO_DIR" a9="--trace=AC_CONFIG_MACRO_DIR_TRACE" a10="--trace=AC_DEFUN" a11="--trace=AC_DEFUN_ONCE" a12="--trace=AC_DEPLIBS_CHECK_METHOD" a13="--trace=AC_DISABLE_FAST_INSTALL" a14="--trace=AC_DISABLE_SHARED" a15="--trace=AC_DISABLE_STATIC" a16="--trace=AC_ENABLE_FAST_INSTALL" a17="--trace=AC_ENABLE_SHARED" a18="--trace=AC_ENABLE_STATIC" a19="--trace=AC_LIBLTDL_CONVENIENCE" a20="--trace=AC_LIBLTDL_INSTALLABLE" a21="--trace=AC_LIBTOOL_COMPILER_OPTION" a22="--trace=AC_LIBTOOL_CONFIG" a23="--trace=AC_LIBTOOL_CXX" a24="--trace=AC_LIBTOOL_DLOPEN" a25="--trace=AC_LIBTOOL_DLOPEN_SELF" a26="--trace=AC_LIBTOOL_F77" a27="--trace=AC_LIBTOOL_FC" a28="--trace=AC_LIBTOOL_GCJ" a29="--trace=AC_LIBTOOL_LANG_CXX_CONFIG" a30="--trace=AC_LIBTOOL_LANG_C_CONFIG" a31="--trace=AC_LIBTOOL_LANG_F77_CONFIG" a32="--trace=AC_LIBTOOL_LANG_GCJ_CONFIG" a33="--trace=AC_LIBTOOL_LANG_RC_CONFIG" a34="--trace=AC_LIBTOOL_LINKER_OPTION" a35="--trace=AC_LIBTOOL_OBJDIR" a36="--trace=AC_LIBTOOL_PICMODE" a37="--trace=AC_LIBTOOL_POSTDEP_PREDEP" a38="--trace=AC_LIBTOOL_PROG_CC_C_O" a39="--trace=AC_LIBTOOL_PROG_COMPILER_NO_RTTI" a40="--trace=AC_LIBTOOL_PROG_COMPILER_PIC" a41="--trace=AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH" a42="--trace=AC_LIBTOOL_PROG_LD_SHLIBS" a43="--trace=AC_LIBTOOL_RC" a44="--trace=AC_LIBTOOL_SETUP" a45="--trace=AC_LIBTOOL_SYS_DYNAMIC_LINKER" a46="--trace=AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE" a47="--trace=AC_LIBTOOL_SYS_HARD_LINK_LOCKS" a48="--trace=AC_LIBTOOL_SYS_LIB_STRIP" a49="--trace=AC_LIBTOOL_SYS_MAX_CMD_LEN" a50="--trace=AC_LIBTOOL_SYS_OLD_ARCHIVE" a51="--trace=AC_LIBTOOL_WIN32_DLL" a52="--trace=AC_LIB_LTDL" a53="--trace=AC_LTDL_DLLIB" a54="--trace=AC_LTDL_DLSYM_USCORE" a55="--trace=AC_LTDL_ENABLE_INSTALL" a56="--trace=AC_LTDL_OBJDIR" a57="--trace=AC_LTDL_PREOPEN" a58="--trace=AC_LTDL_SHLIBEXT" a59="--trace=AC_LTDL_SHLIBPATH" a60="--trace=AC_LTDL_SYMBOL_USCORE" a61="--trace=AC_LTDL_SYSSEARCHPATH" a62="--trace=AC_LTDL_SYS_DLOPEN_DEPLIBS" a63="--trace=AC_PATH_MAGIC" a64="--trace=AC_PATH_TOOL_PREFIX" a65="--trace=AC_PROG_EGREP" a66="--trace=AC_PROG_LD" a67="--trace=AC_PROG_LD_GNU" a68="--trace=AC_PROG_LD_RELOAD_FLAG" a69="--trace=AC_PROG_LIBTOOL" a70="--trace=AC_PROG_NM" a71="--trace=AC_WITH_LTDL" a72="--trace=AM_AUTOMAKE_VERSION" a73="--trace=AM_AUX_DIR_EXPAND" a74="--trace=AM_CONDITIONAL" a75="--trace=AM_DEP_TRACK" a76="--trace=AM_DISABLE_SHARED" a77="--trace=AM_DISABLE_STATIC" a78="--trace=AM_ENABLE_SHARED" a79="--trace=AM_ENABLE_STATIC" a80="--trace=AM_INIT_AUTOMAKE" a81="--trace=AM_MAKE_INCLUDE" a82="--trace=AM_MISSING_HAS_RUN" a83="--trace=AM_MISSING_PROG" a84="--trace=AM_OUTPUT_DEPENDENCY_COMMANDS" a85="--trace=AM_PROG_CC_C_O" a86="--trace=AM_PROG_INSTALL_SH" a87="--trace=AM_PROG_INSTALL_STRIP" a88="--trace=AM_PROG_LD" a89="--trace=AM_PROG_LIBTOOL" a90="--trace=AM_PROG_NM" a91="--trace=AM_RUN_LOG" a92="--trace=AM_SANITY_CHECK" a93="--trace=AM_SET_CURRENT_AUTOMAKE_VERSION" a94="--trace=AM_SET_DEPDIR" a95="--trace=AM_SET_LEADING_DOT" a96="--trace=AM_SILENT_RULES" a97="--trace=AM_SUBST_NOTMAKE" a98="--trace=AU_DEFUN" a99="--trace=LTDL_CONVENIENCE" a100="--trace=LTDL_INIT" a101="--trace=LTDL_INSTALLABLE" a102="--trace=LTOBSOLETE_VERSION" a103="--trace=LTOPTIONS_VERSION" a104="--trace=LTSUGAR_VERSION" a105="--trace=LTVERSION_VERSION" a106="--trace=LT_AC_PROG_EGREP" a107="--trace=LT_AC_PROG_GCJ" a108="--trace=LT_AC_PROG_RC" a109="--trace=LT_AC_PROG_SED" a110="--trace=LT_CMD_MAX_LEN" a111="--trace=LT_CONFIG_LTDL_DIR" a112="--trace=LT_FUNC_ARGZ" a113="--trace=LT_FUNC_DLSYM_USCORE" a114="--trace=LT_INIT" a115="--trace=LT_LANG" a116="--trace=LT_LIB_DLLOAD" a117="--trace=LT_LIB_M" a118="--trace=LT_OUTPUT" a119="--trace=LT_PATH_LD" a120="--trace=LT_PATH_NM" a121="--trace=LT_PROG_GCJ" a122="--trace=LT_PROG_GO" a123="--trace=LT_PROG_RC" a124="--trace=LT_SUPPORTED_TAG" a125="--trace=LT_SYS_DLOPEN_DEPLIBS" a126="--trace=LT_SYS_DLOPEN_SELF" a127="--trace=LT_SYS_DLSEARCH_PATH" a128="--trace=LT_SYS_MODULE_EXT" a129="--trace=LT_SYS_MODULE_PATH" a130="--trace=LT_SYS_SYMBOL_USCORE" a131="--trace=LT_WITH_LTDL" a132="--trace=_AC_AM_CONFIG_HEADER_HOOK" a133="--trace=_AC_PROG_LIBTOOL" a134="--trace=_AM_AUTOCONF_VERSION" a135="--trace=_AM_CONFIG_MACRO_DIRS" a136="--trace=_AM_DEPENDENCIES" a137="--trace=_AM_IF_OPTION" a138="--trace=_AM_MANGLE_OPTION" a139="--trace=_AM_OUTPUT_DEPENDENCY_COMMANDS" a140="--trace=_AM_PROG_CC_C_O" a141="--trace=_AM_PROG_TAR" a142="--trace=_AM_SET_OPTION" a143="--trace=_AM_SET_OPTIONS" a144="--trace=_AM_SUBST_NOTMAKE" a145="--trace=_LTDL_SETUP" a146="--trace=_LT_AC_CHECK_DLFCN" a147="--trace=_LT_AC_FILE_LTDLL_C" a148="--trace=_LT_AC_LANG_CXX" a149="--trace=_LT_AC_LANG_CXX_CONFIG" a150="--trace=_LT_AC_LANG_C_CONFIG" a151="--trace=_LT_AC_LANG_F77" a152="--trace=_LT_AC_LANG_F77_CONFIG" a153="--trace=_LT_AC_LANG_GCJ" a154="--trace=_LT_AC_LANG_GCJ_CONFIG" a155="--trace=_LT_AC_LANG_RC_CONFIG" a156="--trace=_LT_AC_LOCK" a157="--trace=_LT_AC_PROG_CXXCPP" a158="--trace=_LT_AC_PROG_ECHO_BACKSLASH" a159="--trace=_LT_AC_SHELL_INIT" a160="--trace=_LT_AC_SYS_COMPILER" a161="--trace=_LT_AC_SYS_LIBPATH_AIX" a162="--trace=_LT_AC_TAGCONFIG" a163="--trace=_LT_AC_TAGVAR" a164="--trace=_LT_AC_TRY_DLOPEN_SELF" a165="--trace=_LT_CC_BASENAME" a166="--trace=_LT_COMPILER_BOILERPLATE" a167="--trace=_LT_COMPILER_OPTION" a168="--trace=_LT_DLL_DEF_P" a169="--trace=_LT_LIBOBJ" a170="--trace=_LT_LINKER_BOILERPLATE" a171="--trace=_LT_LINKER_OPTION" a172="--trace=_LT_PATH_TOOL_PREFIX" a173="--trace=_LT_PREPARE_SED_QUOTE_VARS" a174="--trace=_LT_PROG_CXX" a175="--trace=_LT_PROG_ECHO_BACKSLASH" a176="--trace=_LT_PROG_F77" a177="--trace=_LT_PROG_FC" a178="--trace=_LT_PROG_LTMAIN" a179="--trace=_LT_REQUIRED_DARWIN_CHECKS" a180="--trace=_LT_WITH_SYSROOT" a181="--trace=_m4_warn" a182="--trace=include" a183="--trace=m4_include" a184="--trace=m4_pattern_allow" a185="--trace=m4_pattern_forbid" a186="--reload-state=/usr/share/autoconf-2.60/autoconf/autoconf.m4f" a187="--undefine=__m4_version__" a188="-" a189="/usr/share/aclocal-1.16/internal/ac-config-macro-dirs.m4" a190="/usr/share/libtool/aclocal/libtool.m4" a191="/usr/share/libtool/aclocal/ltargz.m4" a192="/usr/share/libtool/aclocal/ltdl.m4" a193="/usr/share/libtool/aclocal/ltoptions.m4" a194="/usr/share/libtool/aclocal/ltsugar.m4" a195="/usr/share/libtool/aclocal/ltversion.m4" a196="/usr/share/libtool/aclocal/lt~obsolete.m4" a197="/usr/share/aclocal-1.16/amversion.m4" a198="/usr/share/aclocal-1.16/auxdir.m4" a199="/usr/share/aclocal-1.16/cond.m4" a200="/usr/share/aclocal-1.16/depend.m4" a201="/usr/share/aclocal-1.16/depout.m4" a202="/usr/share/aclocal-1.16/init.m4" a203="/usr/share/aclocal-1.16/install-sh.m4" a204="/usr/share/aclocal-1.16/lead-dot.m4" a205="/usr/share/aclocal-1.16/make.m4" a206="/usr/share/aclocal-1.16/missing.m4" a207="/usr/share/aclocal-1.16/options.m4" a208="/usr/share/aclocal-1.16/prog-cc-c-o.m4" a209="/usr/share/aclocal-1.16/runlog.m4" a210="/usr/share/aclocal-1.16/sanity.m4" a211="/usr/share/aclocal-1.16/silent.m4" a212="/usr/share/aclocal-1.16/strip.m4" a213="/usr/share/aclocal-1.16/substnot.m4" a214="/usr/share/aclocal-1.16/tar.m4" a215="configure.ac" type=CWD msg=audit(1655465404.819:27091): cwd="/usr/src/RPM/BUILD/zlib-1.2.11-alt1/contrib/minizip" type=PATH msg=audit(1655465404.819:27091): item=0 name="/usr/bin/m4" inode=40839 dev=00:30 mode=0100755 ouid=582 ogid=582 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0 type=PATH msg=audit(1655465404.819:27091): item=1 name="/lib64/ld-linux-aarch64.so.1" inode=33874 dev=00:30 mode=0100755 ouid=582 ogid=582 rdev=00:00 nametype=NORMAL cap_fp=0 cap_fi=0 cap_fe=0 cap_fver=0 cap_frootid=0 type=PROCTITLE msg=audit(1655465404.819:27091): proctitle=2F7573722F62696E2F6D34002D2D6E657374696E672D6C696D69743D31303234002D2D676E75002D2D696E636C7564653D2F7573722F73686172652F6175746F636F6E662D322E3630002D2D64656275673D61666C71002D2D666174616C2D7761726E696E67002D2D646562756766696C653D6175746F6D3474652E63616368 audit-userspace-4.0.5/auparse/tty_named_keys.h000066400000000000000000000255261501761310600214600ustar00rootroot00000000000000/* tty_named_keys.h -- * Copyright 2008 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač */ /* Longest sequences should go first, but these are comparatively common. */ E("\x01", "^A") E("\x02", "^B") E("\x03", "^C") // Or "cancel" (3 terms) E("\x04", "^D") E("\x05", "^E") E("\x06", "^F") E("\x07", "^G") E("\x08", "backspace") E("\t", "tab") E("\n", "nl") E("\x0B", "^K") E("\x0C", "^L") E("\r", "ret") E("\x0E", "^N") E("\x0F", "^O") E("\x10", "^P") E("\x11", "^Q") E("\x12", "^R") E("\x13", "^S") E("\x14", "^T") E("\x15", "^U") E("\x16", "^V") E("\x17", "^W") E("\x18", "^X") E("\x19", "^Y") E("\x1A", "^Z") // Or "suspend" (9 terms) /* \x1B handled only after all other escape sequences */ E("\x7F", "backspace") // 59 terms; alternative: "delete" (11 terms) // Based on terminal descriptions in ncrses-base-5.6-20.20080927.fc10. // Conflicts are marked by comments. Ordering: longest sequences first, then // lexicographically. E("\x1B[11;2~", "F13") E("\x1B[11;3~", "F49") E("\x1B[11;4~", "F61") E("\x1B[11;5~", "F25") E("\x1B[11;6~", "F37") E("\x1B[12;2~", "F14") E("\x1B[12;3~", "F50") E("\x1B[12;4~", "F62") E("\x1B[12;5~", "F26") E("\x1B[12;6~", "F38") E("\x1B[13;2~", "F15") E("\x1B[13;3~", "F51") E("\x1B[13;4~", "F63") E("\x1B[13;5~", "F27") E("\x1B[13;6~", "F39") E("\x1B[14;2~", "F16") E("\x1B[14;3~", "F52") E("\x1B[14;5~", "F28") E("\x1B[14;6~", "F40") E("\x1B[15;2~", "F17") E("\x1B[15;3~", "F53") E("\x1B[15;5~", "F29") E("\x1B[15;6~", "F41") E("\x1B[17;2~", "F18") E("\x1B[17;3~", "F54") E("\x1B[17;5~", "F30") E("\x1B[17;6~", "F42") E("\x1B[18;2~", "F19") E("\x1B[18;3~", "F55") E("\x1B[18;5~", "F31") E("\x1B[18;6~", "F43") E("\x1B[19;2~", "F20") E("\x1B[19;3~", "F56") E("\x1B[19;5~", "F32") E("\x1B[19;6~", "F44") E("\x1B[20;2~", "F21") E("\x1B[20;3~", "F57") E("\x1B[20;5~", "F33") E("\x1B[20;6~", "F45") E("\x1B[21;2~", "F22") E("\x1B[21;3~", "F58") E("\x1B[21;5~", "F34") E("\x1B[21;6~", "F46") E("\x1B[23;2~", "F23") E("\x1B[23;3~", "F59") E("\x1B[23;5~", "F35") E("\x1B[23;6~", "F47") E("\x1B[24;2~", "F24") E("\x1B[24;3~", "F60") E("\x1B[24;5~", "F36") E("\x1B[24;6~", "F48") E("\x1B""O1;2A", "scroll-backward") E("\x1B""O1;2B", "scroll-forward") E("\x1B""O1;2C", "shift-right") E("\x1B""O1;2D", "shift-left") E("\x1B[192z", "F11") E("\x1B[193z", "resume") // 3 terms; alternative "F12" (1 term) E("\x1B[194z", "options") // 3 terms; alternative "F13" (1 term) E("\x1B[195z", "undo") // 4 terms; alternative "F14" (1 term) E("\x1B[196z", "help") // 1 term; alternative "F15" (1 term) E("\x1B[197z", "copy") E("\x1B[198z", "F17") E("\x1B[199z", "F18") E("\x1B[1;2A", "scroll-backward") E("\x1B[1;2B", "scroll-forward") E("\x1B[1;2C", "shift-right") E("\x1B[1;2D", "shift-left") E("\x1B[1;2F", "shift-end") E("\x1B[1;2H", "shift-home") E("\x1B[200z", "find") // 1 term; alternative "F19" (1 term) E("\x1B[201z", "F20") E("\x1B[208z", "F31") E("\x1B[209z", "F32") E("\x1B[210z", "F33") E("\x1B[211z", "F34") E("\x1B[212z", "F35") E("\x1B[213z", "F36") E("\x1B[214z", "home") E("\x1B[215z", "F38") E("\x1B[216z", "page-up") E("\x1B[217z", "F40") E("\x1B[218z", "B2") E("\x1B[219z", "F42") E("\x1B[220z", "end") E("\x1B[221z", "F44") E("\x1B[222z", "page-down") // 4 terms; alternative "F45" (1 term) E("\x1B[224z", "F1") E("\x1B[225z", "F2") E("\x1B[226z", "F3") E("\x1B[227z", "F4") E("\x1B[228z", "F5") E("\x1B[229z", "F6") E("\x1B[230z", "F7") E("\x1B[231z", "F8") E("\x1B[232z", "F9") E("\x1B[233z", "F10") E("\x1B[234z", "F11") // 3 terms; alternative "F46" (1 term) E("\x1B[235z", "F12") // 3 terms; alternative "F47" (1 term) E("\x1B[2;2~", "shift-insert") E("\x1B[2;5~", "shift-insert") E("\x1B[3;2~", "shift-del") E("\x1B[3;5~", "shift-del") E("\x1B[5;2~", "shift-previous") E("\x1B[5;5~", "shift-previous") E("\x1B[6;2~", "shift-next") E("\x1B[6;5~", "shift-next") E("\x1B[11^", "F23") E("\x1B[11~", "F1") E("\x1B[12^", "F24") E("\x1B[12~", "F2") E("\x1B[13^", "F25") E("\x1B[13~", "F3") E("\x1B[14^", "F26") E("\x1B[14~", "F4") E("\x1B[15^", "F27") E("\x1B[15~", "F5") E("\x1B[17^", "F28") E("\x1B[17~", "F6") E("\x1B[18^", "F29") E("\x1B[18~", "F7") E("\x1B[19^", "F30") E("\x1B[19~", "F8") E("\x1B[20^", "F31") E("\x1B[20~", "F9") E("\x1B[21^", "F32") E("\x1B[21~", "F10") // 85 terms; alternative "F0" (9 terms) E("\x1B[23$", "F21") E("\x1B[23@", "F43") E("\x1B[23^", "F33") E("\x1B[23~", "F11") E("\x1B[24$", "F22") E("\x1B[24@", "F44") E("\x1B[24^", "F34") E("\x1B[24~", "F12") E("\x1B[25^", "F35") E("\x1B[25~", "F13") E("\x1B[26^", "F36") E("\x1B[26~", "F14") E("\x1B[28^", "F37") E("\x1B[28~", "F15") // 42 terms; alternative "help" (8 terms) E("\x1B[29^", "F38") E("\x1B[29~", "F16") // 42 terms; alternative "redo" (4 terms) E("\x1B[30~", "insert-line") E("\x1B[31^", "F39") E("\x1B[31~", "F17") // 46 terms; alternative "delete-line" (1 term) E("\x1B[32^", "F40") E("\x1B[32~", "F18") E("\x1B[33^", "F41") E("\x1B[33~", "F19") E("\x1B[34^", "F42") E("\x1B[34~", "F20") E("\x1B""O2A", "scroll-backward") E("\x1B""O2B", "scroll-forward") E("\x1B""O2C", "shift-right") E("\x1B""O2D", "shift-left") E("\x1B""O2P", "F13") E("\x1B""O2Q", "F14") E("\x1B""O2R", "F15") E("\x1B""O2S", "F16") E("\x1B""O3P", "F49") E("\x1B""O3Q", "F50") E("\x1B""O3R", "F51") E("\x1B""O3S", "F52") E("\x1B""O4P", "F61") E("\x1B""O4Q", "F62") E("\x1B""O4R", "F63") E("\x1B""O5C", "shift-right") E("\x1B""O5D", "shift-left") E("\x1B""O5F", "shift-end") E("\x1B""O5H", "shift-home") E("\x1B""O5P", "F25") E("\x1B""O5Q", "F26") E("\x1B""O5R", "F27") E("\x1B""O5S", "F28") E("\x1B""O6P", "F37") E("\x1B""O6Q", "F38") E("\x1B""O6R", "F39") E("\x1B""O6S", "F40") E("\x1B[1~", "home") // 30 terms; alternative "find" (42 terms, but "home" is used in Linux) E("\x1B[2$", "shift-insert") E("\x1B[2z", "insert") E("\x1B[2~", "insert") E("\x1B[3$", "shift-del") E("\x1B[3z", "delete") E("\x1B[3~", "delete") E("\x1B[4~", "end") // 30 terms; alternative "select" (42 terms, but "end" is used in Linux) E("\x1B[5$", "shift-previous") E("\x1B[5~", "page-up") // 86 terms; alternative "A3" (4 terms) E("\x1B[6$", "shift-next") E("\x1B[6~", "page-down") // 86 terms; alternative "C3" (4 terms) E("\x1B[7$", "shift-home") E("\x1B[7~", "home") // 17 terms; alternative "A1" (4 terms) E("\x1B[8$", "shift-end") E("\x1B[8^", "delete-eol") E("\x1B[8~", "end") // 17 terms; alternatives "C1" (4 terms), "delete-eol" (1 term) E("\x1B[>M", "mouse") E("\x1B[[A", "F1") E("\x1B[[B", "F2") E("\x1B[[C", "F3") E("\x1B[[D", "F4") E("\x1B[[E", "F5") E("\x9B""11~", "F1") E("\x9B""12~", "F2") E("\x9B""13~", "F3") E("\x9B""14~", "F4") E("\x9B""15~", "F5") E("\x9B""17~", "F6") E("\x9B""18~", "F7") E("\x9B""19~", "F8") E("\x9B""20~", "F9") E("\x9B""21~", "F10") E("\x9B""23~", "F11") E("\x9B""24~", "F12") E("\x9B""25~", "F13") E("\x9B""26~", "F14") E("\x9B""28~", "F15") E("\x9B""29~", "F16") E("\x9B""31~", "F17") E("\x9B""32~", "F18") E("\x9B""33~", "F19") E("\x9B""34~", "F20") E("\x1B""2$", "shift-insert") E("\x1B""OA", "up") E("\x1B""OB", "down") E("\x1B""OC", "right") E("\x1B""OD", "left") E("\x1B""OE", "B2") // 16 terms; alternative "begin" (5 terms) E("\x1B""OF", "end") E("\x1B""OH", "home") E("\x1B""OM", "send") E("\x1B""OP", "F1") E("\x1B""OQ", "F2") E("\x1B""OR", "F3") E("\x1B""OS", "F4") E("\x1B""OT", "F5") E("\x1B""OU", "F6") E("\x1B""OV", "F7") E("\x1B""OW", "F8") E("\x1B""OX", "F9") E("\x1B""OY", "F10") E("\x1B""OZ", "F11") E("\x1B""O[", "F12") E("\x1B""Ol", "F8") E("\x1B""On", "C3") E("\x1B""Op", "C1") E("\x1B""Oq", "C1") // 17 terms; alternatives "A1" (5 terms), "F0" (1 term) E("\x1B""Or", "B2") E("\x1B""Os", "C3") // 17 terms; alternative "A3" (7 terms) E("\x1B""Ot", "F5") E("\x1B""Ou", "B2") // 21 terms; alternative "F6" (4 terms), "begin" (4 terms) E("\x1B""Ov", "F7") E("\x1B""Ow", "A1") // 17 terms; alternative "F9" (4 terms) E("\x1B""Ox", "F10") E("\x1B""Oy", "A3") // 17 terms; alternative "F0" (5 terms) E("\x1B[9", "delete") E("\x1B[@", "F41") // 4 terms; alternative "insert" (3 terms) E("\x1B[A", "up") E("\x1B[B", "down") E("\x1B[C", "right") E("\x1B[D", "left") E("\x1B[E", "B2") // 9 terms; alternative "begin" (1 term) E("\x1B[F", "end") // 5 terms; alternative "lower-left" (3 terms) E("\x1B[G", "B2") // 9 terms; alternative "page-down" (4 terms) E("\x1B[H", "home") E("\x1B[I", "page-up") E("\x1B[L", "insert") E("\x1B[M", "mouse") // 83 terms; alternative "F1" (4 terms) E("\x1B[N", "F2") E("\x1B[O", "F3") E("\x1B[P", "F4") E("\x1B[Q", "F5") E("\x1B[R", "F6") E("\x1B[S", "F7") E("\x1B[T", "F8") E("\x1B[U", "F9") // 4 terms; alternative "page-down" (3 terms) E("\x1B[V", "F10") // 4 terms; alternative "page-dup" (3 terms) E("\x1B[W", "F11") E("\x1B[X", "F12") E("\x1B[Y", "F13") // 4 terms; alternative "end" (3 terms) E("\x1B[Z", "back-tab") // 59 terms; alternative "F14" (4 terms) E("\x1B[[", "F42") E("\x1B[\\", "F43") E("\x1B[]", "F44") E("\x1B[^", "F45") E("\x1B[_", "F46") E("\x1B[`", "F47") E("\x1B[a", "F15") E("\x1B[b", "F16") E("\x1B[c", "shift-right") // 15 terms; alternative "F17" (4 terms) E("\x1B[d", "shift-left") // 15 terms; alternative "F18" (4 terms) E("\x1B[e", "F19") E("\x1B[f", "F20") E("\x1B[g", "F21") E("\x1B[h", "F22") E("\x1B[i", "F23") E("\x1B[j", "F24") E("\x1B[k", "F25") E("\x1B[l", "F26") E("\x1B[m", "F27") E("\x1B[n", "F28") E("\x1B[o", "F29") E("\x1B[p", "F30") E("\x1B[q", "F31") E("\x1B[r", "F32") E("\x1B[s", "F33") E("\x1B[t", "F34") E("\x1B[u", "F35") E("\x1B[v", "F36") E("\x1B[w", "F37") E("\x1B[x", "F38") E("\x1B[y", "F39") E("\x1B[z", "F40") E("\x1B[{", "F48") E("\x9B""1~", "home") E("\x9B""2~", "insert") E("\x9B""3~", "delete") E("\x9B""4~", "end") E("\x9B""5~", "page-up") E("\x9B""6~", "page-down") E("\x1B""A", "up") E("\x1B""B", "down") E("\x1B""C", "right") E("\x1B""D", "left") E("\x1B""F", "end") E("\x1B""J", "clear") E("\x1B""P", "delete") E("\x1B""Q", "insert") E("\x1B""S", "page-down") E("\x1B""T", "page-up") E("\x1B""h", "home") E("\x1B""p", "F1") E("\x1B""q", "F2") E("\x1B""r", "F3") E("\x1B""s", "F4") E("\x1B""t", "F5") E("\x1B""u", "F6") E("\x1B""v", "F7") E("\x1B""w", "F8") E("\x1B\x09", "back-tab") E("\x8F""A", "up") E("\x8F""B", "down") E("\x8F""C", "right") E("\x8F""D", "left") E("\x8F""E", "begin") E("\x8F""M", "send") E("\x8F""q", "C1") E("\x8F""s", "C3") E("\x8F""u", "A3") E("\x8F""w", "A1") E("\x8F""y", "B2") E("\x9B""M", "mouse") E("\x9B""Z", "back-tab") E("\x1B", "esc") audit-userspace-4.0.5/auparse/typetab.h000066400000000000000000000126231501761310600201030ustar00rootroot00000000000000/* typetab.h -- * Copyright 2007-09,2011-12,2014-18,2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(AUPARSE_TYPE_UID, "auid" ) _S(AUPARSE_TYPE_UID, "uid" ) _S(AUPARSE_TYPE_UID, "euid" ) _S(AUPARSE_TYPE_UID, "suid" ) _S(AUPARSE_TYPE_UID, "fsuid" ) _S(AUPARSE_TYPE_UID, "ouid" ) _S(AUPARSE_TYPE_UID, "oauid" ) _S(AUPARSE_TYPE_UID, "old-auid" ) _S(AUPARSE_TYPE_UID, "iuid" ) _S(AUPARSE_TYPE_UID, "id" ) _S(AUPARSE_TYPE_UID, "inode_uid" ) _S(AUPARSE_TYPE_UID, "sauid" ) _S(AUPARSE_TYPE_UID, "obj_uid" ) _S(AUPARSE_TYPE_GID, "obj_gid" ) _S(AUPARSE_TYPE_GID, "gid" ) _S(AUPARSE_TYPE_GID, "egid" ) _S(AUPARSE_TYPE_GID, "sgid" ) _S(AUPARSE_TYPE_GID, "fsgid" ) _S(AUPARSE_TYPE_GID, "ogid" ) _S(AUPARSE_TYPE_GID, "igid" ) _S(AUPARSE_TYPE_GID, "inode_gid" ) _S(AUPARSE_TYPE_GID, "new_gid" ) _S(AUPARSE_TYPE_SYSCALL, "syscall" ) _S(AUPARSE_TYPE_SYSCALL, "uring_op" ) _S(AUPARSE_TYPE_ARCH, "arch" ) _S(AUPARSE_TYPE_EXIT, "exit" ) _S(AUPARSE_TYPE_ESCAPED, "path" ) _S(AUPARSE_TYPE_ESCAPED, "comm" ) _S(AUPARSE_TYPE_ESCAPED, "exe" ) _S(AUPARSE_TYPE_ESCAPED, "file" ) _S(AUPARSE_TYPE_ESCAPED_FILE, "name" ) _S(AUPARSE_TYPE_ESCAPED, "watch" ) _S(AUPARSE_TYPE_ESCAPED, "cwd" ) _S(AUPARSE_TYPE_ESCAPED, "cmd" ) _S(AUPARSE_TYPE_ESCAPED, "acct" ) _S(AUPARSE_TYPE_ESCAPED, "dir" ) _S(AUPARSE_TYPE_ESCAPED_KEY, "key" ) _S(AUPARSE_TYPE_ESCAPED, "vm" ) _S(AUPARSE_TYPE_ESCAPED, "old-chardev" ) _S(AUPARSE_TYPE_ESCAPED, "new-chardev" ) _S(AUPARSE_TYPE_ESCAPED, "old-disk" ) _S(AUPARSE_TYPE_ESCAPED, "new-disk" ) _S(AUPARSE_TYPE_ESCAPED, "old-fs" ) _S(AUPARSE_TYPE_ESCAPED, "new-fs" ) _S(AUPARSE_TYPE_ESCAPED, "old-net" ) _S(AUPARSE_TYPE_ESCAPED, "new-net" ) _S(AUPARSE_TYPE_ESCAPED, "device" ) _S(AUPARSE_TYPE_ESCAPED, "cgroup" ) _S(AUPARSE_TYPE_PERM, "perm" ) _S(AUPARSE_TYPE_PERM, "perm_mask" ) _S(AUPARSE_TYPE_MODE, "mode" ) _S(AUPARSE_TYPE_SOCKADDR, "saddr" ) //_S(AUPARSE_TYPE_FLAGS, "flags" ) deprecated - RHEL4 _S(AUPARSE_TYPE_PROMISC, "prom" ) _S(AUPARSE_TYPE_PROMISC, "old_prom" ) _S(AUPARSE_TYPE_CAPABILITY, "capability" ) _S(AUPARSE_TYPE_SUCCESS, "res" ) _S(AUPARSE_TYPE_SUCCESS, "result" ) _S(AUPARSE_TYPE_A0, "a0" ) _S(AUPARSE_TYPE_A1, "a1" ) _S(AUPARSE_TYPE_A2, "a2" ) _S(AUPARSE_TYPE_A3, "a3" ) _S(AUPARSE_TYPE_SIGNAL, "sig" ) _S(AUPARSE_TYPE_LIST, "list" ) _S(AUPARSE_TYPE_TTY_DATA, "data" ) _S(AUPARSE_TYPE_SESSION, "ses" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_pi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_pe" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_pp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_pa" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_fi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "cap_fp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "fp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "fi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "old_pp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "old_pi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "old_pe" ) _S(AUPARSE_TYPE_CAP_BITMAP, "old_pa" ) _S(AUPARSE_TYPE_CAP_BITMAP, "new_pp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "new_pi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "new_pe" ) _S(AUPARSE_TYPE_CAP_BITMAP, "pp" ) _S(AUPARSE_TYPE_CAP_BITMAP, "pi" ) _S(AUPARSE_TYPE_CAP_BITMAP, "pe" ) _S(AUPARSE_TYPE_CAP_BITMAP, "pa" ) _S(AUPARSE_TYPE_NFPROTO, "family" ) _S(AUPARSE_TYPE_ICMPTYPE, "icmptype" ) _S(AUPARSE_TYPE_PROTOCOL, "proto" ) _S(AUPARSE_TYPE_ADDR, "addr" ) #ifdef WITH_APPARMOR _S(AUPARSE_TYPE_ESCAPED, "apparmor" ) _S(AUPARSE_TYPE_ESCAPED, "operation" ) _S(AUPARSE_TYPE_ESCAPED, "denied_mask" ) _S(AUPARSE_TYPE_ESCAPED, "info" ) _S(AUPARSE_TYPE_ESCAPED, "profile" ) _S(AUPARSE_TYPE_ESCAPED, "requested_mask") #endif _S(AUPARSE_TYPE_PERSONALITY, "per" ) _S(AUPARSE_TYPE_SECCOMP, "code" ) _S(AUPARSE_TYPE_ESCAPED, "old-rng" ) _S(AUPARSE_TYPE_ESCAPED, "new-rng" ) _S(AUPARSE_TYPE_OFLAG, "oflag" ) _S(AUPARSE_TYPE_ESCAPED, "ocomm" ) _S(AUPARSE_TYPE_MMAP, "flags" ) _S(AUPARSE_TYPE_SIGNAL, "sigev_signo" ) _S(AUPARSE_TYPE_MAC_LABEL, "subj" ) _S(AUPARSE_TYPE_MAC_LABEL, "obj" ) _S(AUPARSE_TYPE_MAC_LABEL, "scontext" ) _S(AUPARSE_TYPE_MAC_LABEL, "tcontext" ) _S(AUPARSE_TYPE_MAC_LABEL, "vm-ctx" ) _S(AUPARSE_TYPE_MAC_LABEL, "img-ctx" ) _S(AUPARSE_TYPE_PROCTITLE, "proctitle" ) _S(AUPARSE_TYPE_ESCAPED, "grp" ) _S(AUPARSE_TYPE_ESCAPED, "new_group" ) _S(AUPARSE_TYPE_HOOK, "hook" ) _S(AUPARSE_TYPE_NETACTION, "action" ) _S(AUPARSE_TYPE_MACPROTO, "macproto" ) _S(AUPARSE_TYPE_ESCAPED, "invalid_context") _S(AUPARSE_TYPE_IOCTL_REQ, "ioctlcmd" ) _S(AUPARSE_TYPE_FANOTIFY, "resp" ) _S(AUPARSE_TYPE_ESCAPED, "sw" ) _S(AUPARSE_TYPE_ESCAPED, "root_dir" ) _S(AUPARSE_TYPE_NLMCGRP, "nl-mcgrp" ) _S(AUPARSE_TYPE_RESOLVE, "resolve" ) _S(AUPARSE_TYPE_TRUST, "subj_trust" ) _S(AUPARSE_TYPE_TRUST, "obj_trust" ) _S(AUPARSE_TYPE_FAN_TYPE, "fan_type" ) _S(AUPARSE_TYPE_FAN_INFO, "fan_info" ) _S(AUPARSE_TYPE_ERRNO, "errno" ) audit-userspace-4.0.5/auparse/umounttab.h000066400000000000000000000020531501761310600204450ustar00rootroot00000000000000/* umounttab.h -- * Copyright 2013 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Location: include/linux/fs.h */ _S(0x00000001, "MNT_FORCE" ) _S(0x00000002, "MNT_DETACH" ) _S(0x00000004, "MNT_EXPIRE" ) _S(0x00000008, "UMOUNT_NOFOLLOW" ) _S(0x80000000, "UMOUNT_UNUSED" ) audit-userspace-4.0.5/auparse/xattr-atflagtab.h000066400000000000000000000017761501761310600215270ustar00rootroot00000000000000/* xattr-at-flagtab.h -- * Copyright Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Attila Lakatos * Location: fs/xattr.c */ // Handled in the code _S(00, "LOOKUP_FOLLOW" ) _S(0x100, "AT_SYMLINK_NOFOLLOW" ) _S(0x1000, "AT_EMPTY_PATH" ) audit-userspace-4.0.5/bindings/000077500000000000000000000000001501761310600164135ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/Makefile.am000066400000000000000000000017271501761310600204560ustar00rootroot00000000000000# Makefile.am -- # Copyright 2007,2014-16 Red Hat Inc., Durham, North Carolina. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig SUBDIRS = python golang swig audit-userspace-4.0.5/bindings/golang/000077500000000000000000000000001501761310600176625ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/golang/Makefile.am000066400000000000000000000032341501761310600217200ustar00rootroot00000000000000# Makefile.am -- # Copyright 2014,16 Red Hat Inc., Durham, North Carolina. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = audit.go dist_check_SCRIPTS = test.go if HAVE_GOLANG LIBDIR = lib GODIR = $(LIBDIR)/golang/src/pkg/redhat.com/audit install: [ -d $(DESTDIR)${prefix}/$(GODIR) ] || mkdir -p $(DESTDIR)${prefix}/$(GODIR) install -m 644 ${top_srcdir}/bindings/golang/audit.go $(DESTDIR)${prefix}/$(GODIR) uninstall: @rm -f $(DESTDIR)${prefix}/$(GODIR)/* check: @mkdir audit @cp ${top_srcdir}/bindings/golang/audit.go audit @cp ${top_srcdir}/lib/libaudit.h audit ## Disable for now. Golang doesn't allow overriding search ## paths from the command line. ##[ -f test.go ] || cp ${top_srcdir}/bindings/golang/test.go . ##PKG_CONFIG_PATH=${abs_top_builddir}/lib/:$(PKG_CONFIG_PATH) GOPATH=$(pwd) $(GOLANG) run test.go @rm -rf audit endif audit-userspace-4.0.5/bindings/golang/audit.go000066400000000000000000000031511501761310600213170ustar00rootroot00000000000000package audit /* The audit package is a go bindings to libaudit that only allows for logging audit events. Author Steve Grubb */ // #cgo pkg-config: audit // #include "libaudit.h" // #include // #include // #include // #include import "C" import ( "unsafe" ) const ( AUDIT_VIRT_CONTROL = 2500 AUDIT_VIRT_RESOURCE = 2501 AUDIT_VIRT_MACHINE_ID = 2502 ) // type=VIRT_CONTROL msg=audit(08/05/2014 17:01:05.891:6471) : pid=1265 uid=root auid=unset ses=unset subj=system_u:system_r:virtd_t:s0-s0:c0.c1023 msg='virt=kvm op=start reason=booted vm=vm1 uuid=462dcd6d-fb68-4a26-a96f-56eb024515b9 vm-pid=22527 exe=/usr/sbin/libvirtd hostname=? addr=? terminal=? res=success' func AuditValueNeedsEncoding(str string) bool { cstr := C.CString(str) defer C.free(unsafe.Pointer(cstr)) len := C.strlen(cstr) res, _ := C.audit_value_needs_encoding(cstr, C.uint(len)) if res != 0 { return true } return false } func AuditEncodeNVString(name string, value string) string { cname := C.CString(name) cval := C.CString(value) cres := C.audit_encode_nv_string(cname, cval, 0) C.free(unsafe.Pointer(cname)) C.free(unsafe.Pointer(cval)) defer C.free(unsafe.Pointer(cres)) return C.GoString(cres) } func AuditLogUserEvent(event_type int, message string, result bool) error { var r int fd := C.audit_open() if result { r = 1 } else { r = 0 } if fd != -1 { cmsg := C.CString(message) _, err := C.audit_log_user_message(fd, C.int(event_type), cmsg, nil, nil, nil, C.int(r)) C.free(unsafe.Pointer(cmsg)) C.close(fd) return err } return nil } audit-userspace-4.0.5/bindings/golang/test.go000066400000000000000000000004131501761310600211660ustar00rootroot00000000000000package main import ( "./audit" "fmt" ) func main() { if audit.AuditValueNeedsEncoding("test") { fmt.Printf("Failed test 1\n") return } if !audit.AuditValueNeedsEncoding("test test") { fmt.Printf("Failed test 2\n") return } fmt.Printf("Success\n") } audit-userspace-4.0.5/bindings/python/000077500000000000000000000000001501761310600177345ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/python/Makefile.am000066400000000000000000000001731501761310600217710ustar00rootroot00000000000000CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = auparse_python.c SUBDIRS = if USE_PYTHON3 SUBDIRS += python3 endif audit-userspace-4.0.5/bindings/python/auparse_python.c000066400000000000000000002405271501761310600231530ustar00rootroot00000000000000#define PY_SSIZE_T_CLEAN #include #include "structmember.h" #include #include #include "auparse.h" /* auparse functions explicitly not exported in this binding and why: auparse_destroy: because this is handled by python object management auparse_get_time: because AuEvent provides this as an attribute auparse_get_milli: because AuEvent provides this as an attribute auparse_get_serial: because AuEvent provides this as an attribute auparse_get_node: because AuEvent provides this as an attribute auparse_timestamp_compare: because AuEvent calls this via the cmp operator */ /* * Note about function return codes. If a C function returns: * * -1 and 0, then we return exception and none respectively * -1, 0, 1, then we return exception, false, true respectively * */ #if PY_MINOR_VERSION >= 5 #define USE_RICH_COMPARISON #endif #define MODINITERROR return NULL #define PYNUM_FROMLONG PyLong_FromLong #define PYSTR_CHECK PyUnicode_Check #define PYSTR_FROMSTRING PyUnicode_FromString #define PYSTR_ASSTRING PyUnicode_AsUTF8 #define PYFILE_ASFILE(f) fdopen(PyObject_AsFileDescriptor(f), "r") int PyFile_Check(PyObject *f) { PyObject *io, *base; if (!(io = PyImport_ImportModule("io"))) { return 0; } else { if (!(base = PyObject_GetAttrString(io, "TextIOBase"))) { return 0; } else { return PyObject_IsInstance(f, base); } } } static int debug = 0; static PyObject *NoParserError = NULL; /*=========================================================================== * AuEvent *===========================================================================*/ typedef struct { PyObject_HEAD PyObject *sec; PyObject *milli; PyObject *serial; PyObject *host; au_event_t event; } AuEvent; static void AuEvent_dealloc(AuEvent* self) { Py_XDECREF(self->sec); Py_XDECREF(self->milli); Py_XDECREF(self->serial); Py_XDECREF(self->host); Py_TYPE(self)->tp_free((PyObject*)self); } #ifdef USE_RICH_COMPARISON static PyObject * AuEvent_rich_compare(PyObject *obj1, PyObject *obj2, int op) { PyObject *result = Py_False; AuEvent *au_event1 = (AuEvent *)obj1; AuEvent *au_event2 = (AuEvent *)obj2; int res = auparse_timestamp_compare(&au_event1->event, &au_event2->event); switch (op) { case Py_LT: if (res < 0) result = Py_True; break; case Py_EQ: if (res == 0) result = Py_True; break; case Py_GT: if (res > 0) result = Py_True; break; default: result = Py_NotImplemented; break; } Py_INCREF(result); return result; } #else static int AuEvent_compare(PyObject *obj1, PyObject *obj2) { AuEvent *au_event1 = (AuEvent *) obj1; AuEvent *au_event2 = (AuEvent *) obj2; return auparse_timestamp_compare(&au_event1->event, &au_event2->event); } #endif static PyObject * AuEvent_get_sec(AuEvent *self, void *closure) { if (self->sec == NULL) { if ((self->sec = PYNUM_FROMLONG(self->event.sec)) == NULL) return NULL; } Py_INCREF(self->sec); return self->sec; } static PyObject * AuEvent_get_milli(AuEvent *self, void *closure) { if (self->milli == NULL) { if ((self->milli = PYNUM_FROMLONG(self->event.milli)) == NULL) return NULL; } Py_INCREF(self->milli); return self->milli; } static PyObject * AuEvent_get_serial(AuEvent *self, void *closure) { if (self->serial == NULL) { if ((self->serial = PYNUM_FROMLONG(self->event.serial)) == NULL) return NULL; } Py_INCREF(self->serial); return self->serial; } static PyObject * AuEvent_get_host(AuEvent *self, void *closure) { if (self->event.host == NULL) { Py_RETURN_NONE; } else { if (self->host == NULL) { if ((self->host = PYSTR_FROMSTRING(self->event.host)) == NULL) return NULL; } Py_INCREF(self->host); return self->host; } } static PyGetSetDef AuEvent_getsetters[] = { {"sec", (getter)AuEvent_get_sec, (setter)NULL, "Event seconds", NULL}, {"milli", (getter)AuEvent_get_milli, (setter)NULL, "millisecond of the timestamp", NULL}, {"serial", (getter)AuEvent_get_serial, (setter)NULL, "Serial number of the event", NULL}, {"host", (getter)AuEvent_get_host, (setter)NULL, "Machine's name", NULL}, {NULL} /* Sentinel */ }; static PyMemberDef AuEvent_members[] = { {NULL} /* Sentinel */ }; static char * fmt_event(time_t seconds, unsigned int milli, unsigned long serial, const char *host) { static char buf1[200], buf2[200]; char fmt[] = "%a %b %d %H:%M:%S.%%ld %Y serial=%%ld host=%%s"; struct tm *tmp; tmp = localtime(&seconds); if (tmp == NULL) { sprintf(buf2, "localtime error"); return buf2; } if (strftime(buf1, sizeof(buf1), fmt, tmp) == 0) { sprintf(buf2, "strftime returned 0"); return buf2; } snprintf(buf2, sizeof(buf2), buf1, milli, serial, host, sizeof(buf2)); return buf2; } static PyObject * AuEvent_str(PyObject * obj) { AuEvent *event = (AuEvent *) obj; return PYSTR_FROMSTRING(fmt_event(event->event.sec, event->event.milli, event->event.serial, event->event.host)); } static PyMethodDef AuEvent_methods[] = { {NULL} /* Sentinel */ }; PyDoc_STRVAR(AuEvent_doc, "An internal object which encapsulates the timestamp, serial number\n\ and host information of an audit event. The object cannot be\n\ instantiated from python code, rather it is returned from the\n\ audit parsing API."); static PyTypeObject AuEventType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "auparse.AuEvent", .tp_basicsize = sizeof(AuEvent), .tp_dealloc = (destructor)AuEvent_dealloc, #ifdef USE_RICH_COMPARISON .tp_richcompare = AuEvent_rich_compare, #else .tp_compare = AuEvent_compare, #endif .tp_str = AuEvent_str, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = AuEvent_doc, .tp_methods = AuEvent_methods, .tp_members = AuEvent_members, .tp_getset = AuEvent_getsetters, }; static PyObject * AuEvent_new_from_struct(au_event_t const *event_ptr) { AuEvent *self; self = (AuEvent *)AuEventType.tp_alloc(&AuEventType, 0); if (self != NULL) { self->event = *event_ptr; } return (PyObject *)self; } /*=========================================================================== * AuParser *===========================================================================*/ #define PARSER_CHECK \ if (self->au == NULL) { \ PyErr_SetString(NoParserError, "object has no parser associated with it"); \ return NULL; \ } typedef struct { PyObject_HEAD auparse_state_t *au; } AuParser; typedef struct { AuParser *py_AuParser; PyObject *func; PyObject *user_data; } CallbackData; void callback_data_destroy(void *user_data) { CallbackData *cb = (CallbackData *)user_data; if (debug) printf("<< callback_data_destroy\n"); if (cb) { Py_DECREF(cb->func); Py_XDECREF(cb->user_data); PyMem_Del(cb); } } /* * This function is hard coded into the python bindings for the * AuParser_add_callback function as the receiver of any callbacks. It * gets the data from auparse and builds up a python function call based * on the saved data set during the add callback. */ static void auparse_callback(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { CallbackData *cb = (CallbackData *)user_data; PyObject *arglist; PyObject *result; if (debug) printf("<< auparse_callback\n"); arglist = Py_BuildValue("OiO", cb->py_AuParser, cb_event_type, cb->user_data); #if PY_MINOR_VERSION >= 12 result = PyObject_CallObject(cb->func, arglist); #else result = PyEval_CallObject(cb->func, arglist); #endif Py_DECREF(arglist); Py_XDECREF(result); } static void AuParser_dealloc(AuParser* self) { if (debug) printf("<< AuParser_dealloc: self=%p au=%p\n", self, self->au); if (self->au != NULL) { auparse_destroy(self->au); } Py_TYPE(self)->tp_free((PyObject*)self); } static PyObject * AuParser_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { AuParser *self; self = (AuParser *)type->tp_alloc(type, 0); if (self != NULL) { self->au = NULL; } return (PyObject *)self; } /******************************** * auparse_init ********************************/ static int AuParser_init(AuParser *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"source_type", "source", NULL}; int source_type = -1; PyObject *source=Py_None; if (self->au != NULL) { auparse_destroy(self->au); self->au = NULL; } if (! PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, &source_type, &source)) return -1; switch (source_type) { case AUSOURCE_LOGS: { if (source != Py_None) { PyErr_SetString(PyExc_ValueError, "source must be None or not passed as a parameter when source_type is AUSOURCE_LOGS"); return -1; } if ((self->au = auparse_init(source_type, NULL)) == NULL) { PyErr_SetFromErrno(PyExc_IOError); return -1; } } break; case AUSOURCE_FILE: { const char *filename = NULL; if (!PYSTR_CHECK(source)) { PyErr_SetString(PyExc_ValueError, "source must be a string when source_type is AUSOURCE_FILE"); return -1; } if ((filename = PYSTR_ASSTRING(source)) == NULL) return -1; if ((self->au = auparse_init(source_type, filename)) == NULL) { PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); return -1; } } break; case AUSOURCE_FILE_ARRAY: { int i, n; PyObject *item = NULL; const char **files = NULL; if (PySequence_Check(source)) { n = PySequence_Size(source); if ((files = (const char **)PyMem_New(char *, n+1)) == NULL) { PyErr_NoMemory(); return -1; } for (i = 0; i < n; i++) { item = PySequence_GetItem(source, i); if ((files[i] = PYSTR_ASSTRING(item)) == NULL) { PyErr_SetString(PyExc_ValueError, "members of source sequence must be a string when source_type is AUSOURCE_FILE_ARRAY"); Py_DECREF(item); PyMem_Del(files); return -1; } else { Py_DECREF(item); } } files[i] = NULL; } else { PyErr_SetString(PyExc_ValueError, "source must be a sequence when source_type is AUSOURCE_FILE_ARRAY"); return -1; } if ((self->au = auparse_init(source_type, files)) == NULL) { PyErr_SetFromErrno(PyExc_IOError); PyMem_Del(files); return -1; } PyMem_Del(files); } break; case AUSOURCE_BUFFER: { const char *buf; if ((buf = PYSTR_ASSTRING(source)) == NULL) return -1; if ((self->au = auparse_init(source_type, buf)) == NULL) { PyErr_SetFromErrno(PyExc_EnvironmentError); return -1; } } break; case AUSOURCE_BUFFER_ARRAY: { int i, n; PyObject *item = NULL; const char **buffers = NULL; if (PySequence_Check(source)) { n = PySequence_Size(source); if ((buffers = (const char **)PyMem_New(char *, n+1)) == NULL) { PyErr_NoMemory(); return -1; } for (i = 0; i < n; i++) { item = PySequence_GetItem(source, i); if ((buffers[i] = PYSTR_ASSTRING(item)) == NULL) { PyErr_SetString(PyExc_ValueError, "members of source sequence must be a string when source_type is AUSOURCE_BUFFER_ARRAY"); Py_DECREF(item); PyMem_Del(buffers); return -1; } else { Py_DECREF(item); } } buffers[i] = NULL; } else { PyErr_SetString(PyExc_ValueError, "source must be a sequence when source_type is AUSOURCE_FILE_ARRAY"); return -1; } if ((self->au = auparse_init(source_type, buffers)) == NULL) { PyErr_SetFromErrno(PyExc_EnvironmentError); PyMem_Del(buffers); return -1; } PyMem_Del(buffers); } break; case AUSOURCE_DESCRIPTOR: { long fd; fd = PyObject_AsFileDescriptor(source); if (fd < 0) { PyErr_SetString(PyExc_ValueError, "source must be resolvable to a file descriptor when source_type is AUSOURCE_DESCRIPTOR"); return -1; } if ((self->au = auparse_init(source_type, (const void *)fd)) == NULL) { PyErr_SetFromErrno(PyExc_EnvironmentError); return -1; } } break; case AUSOURCE_FILE_POINTER: { FILE* fp; if (!PyFile_Check(source)) { PyErr_SetString(PyExc_ValueError, "source must be a file object when source_type is AUSOURCE_FILE_POINTER"); return -1; } if ((fp = PYFILE_ASFILE(source)) == NULL) { PyErr_SetString(PyExc_TypeError, "source must be open file when source_type is AUSOURCE_FILE_POINTER"); return -1; } const char *filename = NULL; #if PY_MAJOR_VERSION < 3 int fd = fileno(fp); fp = fdopen(fd, "r"); /* PyFile_Name is available in Python 2 */ filename = PYSTR_ASSTRING(PyFile_Name(source)); #else /* In Python 3 obtain the name attribute if possible */ PyObject *name_obj = PyObject_GetAttrString(source, "name"); if (name_obj && PYSTR_CHECK(name_obj)) filename = PYSTR_ASSTRING(name_obj); Py_XDECREF(name_obj); #endif if ((self->au = auparse_init(source_type, fp)) == NULL) { if (filename) PyErr_SetFromErrnoWithFilename(PyExc_IOError, filename); else PyErr_SetFromErrno(PyExc_IOError); return -1; } } break; case AUSOURCE_FEED: { if (source != Py_None) { PyErr_SetString(PyExc_ValueError, "source must be None when source_type is AUSOURCE_FEED"); return -1; } if ((self->au = auparse_init(source_type, NULL)) == NULL) { PyErr_SetFromErrno(PyExc_EnvironmentError); return -1; } } break; default: { PyErr_SetString(PyExc_ValueError, "Invalid source type"); return -1; } break; } if (debug) printf(">> AuParser_init: self=%p au=%p\n", self, self->au); return 0; } /******************************** * auparse_feed ********************************/ PyDoc_STRVAR(feed_doc, "feed(data) supplies new data for the parser to consume.\n\ \n\ AuParser() must have been called with a source type of AUSOURCE_FEED.\n\ The parser consumes as much data as it can invoking a user supplied\n\ callback specified with add_callback() with a cb_event_type of\n\ AUPARSE_CB_EVENT_READY each time the parser recognizes a complete event\n\ in the data stream. Data not fully parsed will persist and be prepended\n\ to the next feed data. After all data has been feed to the parser flush_feed()\n\ should be called to signal the end of input data and flush any pending\n\ parse data through the parsing system.\n\ \n\ Returns None.\n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_feed(AuParser *self, PyObject *args) { char *data; Py_ssize_t data_len; int result; if (!PyArg_ParseTuple(args, "s#:feed", &data, &data_len)) return NULL; PARSER_CHECK; if (debug) printf("<< AuParser_feed\n"); result = auparse_feed(self->au, data, data_len); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_feed_age_events ********************************/ PyDoc_STRVAR(feed_age_events_doc, "feed_age_events() age events by the clock\n\ \n\ feed_age_events() should be called to timeout events by the clock.\n\ Any newly complete events will be sent to the callback function.\n\ \n\ Returns None.\n\ "); static PyObject * AuParser_feed_age_events(AuParser *self) { PARSER_CHECK; auparse_feed_age_events(self->au); Py_RETURN_NONE; } /******************************** * auparse_flush_feed ********************************/ PyDoc_STRVAR(flush_feed_doc, "flush_feed() flush any unconsumed feed data through parser\n\ \n\ flush_feed() should be called to signal the end of feed input data\n\ and flush any pending parse data through the parsing system.\n\ \n\ Returns None.\n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_flush_feed(AuParser *self) { int result; PARSER_CHECK; result = auparse_flush_feed(self->au); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_feed_has_data ********************************/ PyDoc_STRVAR(feed_has_data_doc, "feed_has_data() determines if there are any records that\n\ are accumulating but not yet ready to emit.\n\ \n\ Returns True if data left and false otherwise.\n\ "); static PyObject * AuParser_feed_has_data(AuParser *self) { PARSER_CHECK; if (auparse_feed_has_data(self->au) == 0) Py_RETURN_FALSE; Py_RETURN_TRUE; } /******************************** * auparse_feed_has_data ********************************/ PyDoc_STRVAR(feed_has_ready_event_doc, "feed_has_ready_event() determines if there are any events that are\n\ ready to emit.\n\ \n\ Returns True if event is ready and false otherwise.\n\ "); static PyObject * AuParser_feed_has_ready_event(AuParser *self) { PARSER_CHECK; if (auparse_feed_has_ready_event(self->au) == 0) Py_RETURN_FALSE; Py_RETURN_TRUE; } /******************************** * auparse_add_callback ********************************/ PyDoc_STRVAR(add_callback_doc, "add_callback(callback, user_data) add a callback handler for notifications.\n\ \n\ auparse_add_callback adds a callback function to the parse state which\n\ is invoked to notify the application of parsing events.\n\ \n\ The signature of the callback is:\n\ \n\ callback(au, cb_event_type,user_data)\n\ \n\ When the callback is invoked it is passed:\n\ au: the AuParser object\n\ cb_event_type: enumerated value indicating the reason why the callback was invoked\n\ user_data: user supplied private data\n\ \n\ The cb_event_type argument indicates why the callback was invoked.\n\ It's possible values are:\n\ \n\ AUPARSE_CB_EVENT_READY\n\ A complete event has been parsed and is ready to be examined.\n\ This is logically equivalent to the parse state immediately following\n\ auparse_next_event()\n\ \n\ Returns None.\n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_add_callback(AuParser *self, PyObject *args) { PyObject *func; PyObject *user_data = NULL; if (!PyArg_ParseTuple(args, "O|O:add_callback", &func, &user_data)) return NULL; if (!PyFunction_Check(func)) { PyErr_SetString(PyExc_ValueError, "callback must be a function"); return NULL; } PARSER_CHECK; { /* * The way this works is that we gather up all of the pieces that * were passed to the bindings and bundle them up in a callback data * structure and register _that_ with the auparse library. This user * supplied data is then used in the callback to rebuild a python * function call which is then called. */ CallbackData *cb; cb = PyMem_New(CallbackData, 1); if (cb == NULL) return PyErr_NoMemory(); cb->py_AuParser = self; cb->func = func; /* * The second parameter to this function is optional. If it were not * passed, convert it to the None object for the python function * call later. */ if (user_data == NULL) user_data = Py_None; cb->user_data = user_data; Py_INCREF(cb->func); Py_XINCREF(cb->user_data); auparse_add_callback(self->au, auparse_callback, cb, callback_data_destroy); } Py_RETURN_NONE; } /******************************** * auparse_set_escape_mode ********************************/ PyDoc_STRVAR(set_escape_mode_doc, "set_escape_mode(mode) Set audit parser escaping\n\ \n\ This function sets the character escaping applied to value fields in the audit record.\n\ Returns None.\n\ "); static PyObject * AuParser_set_escape_mode(AuParser *self, PyObject *args) { int mode; if (!PyArg_ParseTuple(args, "i", &mode)) return NULL; auparse_set_escape_mode(self->au, mode); Py_RETURN_NONE; } /******************************** * auparse_set_eoe_timeout ********************************/ PyDoc_STRVAR(set_eoe_timeout_doc, "set_eoe_timeout(tmo) Set audit parser end of event timeout\n\ \n\ This function sets the timeout used to determine if an event is complete.\n\ Returns None.\n\ "); static PyObject * AuParser_set_eoe_timeout(AuParser *self, PyObject *args) { int tmo; if (!PyArg_ParseTuple(args, "i", &tmo)) return NULL; auparse_set_eoe_timeout(tmo); Py_RETURN_NONE; } /******************************** * auparse_reset ********************************/ PyDoc_STRVAR(reset_doc, "reset() Reset audit parser instance\n\ \n\ reset resets all internal cursors to the beginning.\n\ It closes files and descriptors.\n\ \n\ Returns None.\n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_reset(AuParser *self) { int result; PARSER_CHECK; result = auparse_reset(self->au); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_metrics ********************************/ PyDoc_STRVAR(metrics_doc, "metrics() Returns gets some basic information about auparse's internalstate.\n\ \n\ Returns a string holding metrics\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_metrics(AuParser *self) { char *value = NULL; PARSER_CHECK; value = auparse_metrics(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "metrics returned NULL"); return NULL; } PyObject *obj = Py_BuildValue("s", value); free(value); return obj; } /******************************** * ausearch_add_expression ********************************/ PyDoc_STRVAR(search_add_expression_doc, "search_add_expression(expression, how) Build up search expression\n\ \n\ \n\ ausearch_add_item adds an expression to the current audit search\n\ expression. The search conditions can then be used to scan logs,\n\ files, or buffers for something of interest. The expression parameter\n\ contains an expression, as specified in ausearch-expression(5).\n\ \n\ The how parameter determines how this search expression will affect the\n\ existing search expression, if one is already defined. The possible\n\ values are:\n\ \n\ AUSEARCH_RULE_CLEAR:\n\ Clear the current search expression, if any, and use only this search\n\ expression.\n\ \n\ AUSEARCH_RULE_OR:\n\ \n\ If a search expression E is already configured, replace it by\n\ (E || this_search_expression).\n\ \n\ AUSEARCH_RULE_AND:\n\ If a search expression E is already configured, replace it by\n\ (E && this_search_expression).\n\ \n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_search_add_expression(AuParser *self, PyObject *args) { const char *expression; char *error; int how; int result; if (!PyArg_ParseTuple(args, "si", &expression, &how)) return NULL; PARSER_CHECK; result = ausearch_add_expression(self->au, expression, &error, how); if (result == 0) Py_RETURN_NONE; if (error == NULL) PyErr_SetFromErrno(PyExc_EnvironmentError); else { PyErr_SetString(PyExc_EnvironmentError, error); free(error); } return NULL; } /******************************** * ausearch_add_item ********************************/ PyDoc_STRVAR(search_add_item_doc, "search_add_item(field, op, value, how) Build up search rule\n\ \n\ \n\ search_add_item() adds one search condition to the current audit search\n\ expression. The search conditions can then be used to scan logs, files, or\n\ buffers for something of interest. The field value is the field name\n\ that the value will be checked for. The op variable describes what\n\ kind of check is to be done. Legal op values are:\n\ \n\ 'exists':\n\ Just check that a field name exists\n\ \n\ '=':\n\ locate the field name and check that the value associated with it\n\ is equal to the value given in this rule.\n\ \n\ '!=':\n\ locate the field name and check that the value associated with\n\ it is NOT equal to the value given in this rule.\n\ \n\ The value parameter is compared to the uninterpreted field value.\n\ \n\ The how parameter determines how this search expression will affect the\n\ existing search expression, if one is already defined. The possible\n\ values are:\n\ \n\ AUSEARCH_RULE_CLEAR:\n\ Clear the current search expression, if any, and use only this search\n\ expression.\n\ \n\ AUSEARCH_RULE_OR:\n\ \n\ If a search expression E is already configured, replace it by\n\ (E || this_search_expression).\n\ \n\ AUSEARCH_RULE_AND:\n\ If a search expression E is already configured, replace it by\n\ (E && this_search_expression).\n\ \n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_search_add_item(AuParser *self, PyObject *args) { const char *field; const char *op; const char *value; int how; int result; if (!PyArg_ParseTuple(args, "sssi", &field, &op, &value, &how)) return NULL; PARSER_CHECK; result = ausearch_add_item(self->au, field, op, value, how); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * ausearch_add_interpreted_item ********************************/ PyDoc_STRVAR(search_add_interpreted_item_doc, "search_add_interpreted_item(field, op, value, how) Build up search rule\n\ \n\ \n\ search_add_interpreted_item() adds one search condition to the current audit\n\ search expression. The search conditions can then be used to scan logs,\n\ files, or buffers for something of interest. The field value is the field\n\ name that the value will be checked for. The op variable describes what\n\ kind of check is to be done. Legal op values are:\n\ \n\ 'exists':\n\ Just check that a field name exists\n\ \n\ '=':\n\ locate the field name and check that the value associated with it\n\ is equal to the value given in this rule.\n\ \n\ '!=':\n\ locate the field name and check that the value associated with\n\ it is NOT equal to the value given in this rule.\n\ \n\ The value parameter is compared to the interpreted field value (the value\n\ that would be returned by AuParser.interpret_field).\n\ \n\ The how parameter determines how this search expression will affect the\n\ existing search expression, if one is already defined. The possible\n\ values are:\n\ \n\ AUSEARCH_RULE_CLEAR:\n\ Clear the current search expression, if any, and use only this search\n\ expression.\n\ \n\ AUSEARCH_RULE_OR:\n\ \n\ If a search expression E is already configured, replace it by\n\ (E || this_search_expression).\n\ \n\ AUSEARCH_RULE_AND:\n\ If a search expression E is already configured, replace it by\n\ (E && this_search_expression).\n\ \n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_search_add_interpreted_item(AuParser *self, PyObject *args) { const char *field; const char *op; const char *value; int how; int result; if (!PyArg_ParseTuple(args, "sssi", &field, &op, &value, &how)) return NULL; PARSER_CHECK; result = ausearch_add_interpreted_item(self->au, field, op, value, how); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * ausearch_add_timestamp_item ********************************/ PyDoc_STRVAR(search_add_timestamp_item_doc, "search_add_timestamp_item(op, sec, milli, how) Build up search rule\n\ \n\ \n\ search_add_timestamp_item adds an event time condition to the current audit\n\ search expression. The search conditions can then be used to scan logs,\n\ files, or buffers for something of interest. The op parameter specifies the\n\ desired comparison. Legal op values are \"<\", \"<=\", \">=\", \">\" and\n\ \"=\". The left operand of the comparison operator is the timestamp of the\n\ examined event, the right operand is specified by the sec and milli\n\ parameters.\n\ \n\ The how parameter determines how this search expression will affect the\n\ existing search expression, if one is already defined. The possible\n\ values are:\n\ \n\ AUSEARCH_RULE_CLEAR:\n\ Clear the current search expression, if any, and use only this search\n\ expression.\n\ \n\ AUSEARCH_RULE_OR:\n\ \n\ If a search expression E is already configured, replace it by\n\ (E || this_search_expression).\n\ \n\ AUSEARCH_RULE_AND:\n\ If a search expression E is already configured, replace it by\n\ (E && this_search_expression).\n\ \n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_search_add_timestamp_item(AuParser *self, PyObject *args) { const char *op; PY_LONG_LONG sec; int milli; int how; int result; /* There's no completely portable way to handle time_t values from Python; note that time_t might even be a floating-point type! PY_LONG_LONG is at least enough not to worry about year 2038. milli is int because Python's 'I' format does no overflow checking. Negative milli values will wrap to values > 1000 and ausearch_add_timestamp_item will reject them. */ if (!PyArg_ParseTuple(args, "sLii", &op, &sec, &milli, &how)) return NULL; PARSER_CHECK; result = ausearch_add_timestamp_item(self->au, op, sec, (unsigned)milli, how); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * ausearch_add_timestamp_item_ex ********************************/ PyDoc_STRVAR(search_add_timestamp_item_ex_doc, "search_add_timestamp_item_ex(op, sec, milli, serial, how) Build up search rule\n\ search_add_timestamp_item_ex adds an event time condition to the current audit\n\ search expression. Its similar to search_add_timestamp_item except it adds\n\ the event serial number.\n\ "); static PyObject * AuParser_search_add_timestamp_item_ex(AuParser *self, PyObject *args) { const char *op; PY_LONG_LONG sec; int milli; int serial; int how; int result; /* There's no completely portable way to handle time_t values from Python; note that time_t might even be a floating-point type! PY_LONG_LONG is at least enough not to worry about year 2038. milli is int because Python's 'I' format does no overflow checking. Negative milli values will wrap to values > 1000 and ausearch_add_timestamp_item will reject them. */ if (!PyArg_ParseTuple(args, "sLiiii", &op, &sec, &milli, &serial, &how)) return NULL; PARSER_CHECK; result = ausearch_add_timestamp_item_ex(self->au, op, sec, (unsigned)milli, (unsigned)serial, how); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * ausearch_add_regex ********************************/ PyDoc_STRVAR(search_add_regex_doc, "search_add_regex(regexp) Add a regular expression to the search criteria.\n\ \n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_search_add_regex(AuParser *self, PyObject *args) { const char *regexp; int result; if (!PyArg_ParseTuple(args, "s", ®exp)) return NULL; PARSER_CHECK; result = ausearch_add_regex(self->au, regexp); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * ausearch_set_stop ********************************/ PyDoc_STRVAR(search_set_stop_doc, "search_set_stop(where) Set where cursor is positioned on search match.\n\ \n\ search_set_stop() determines where the internal cursor will stop when\n\ a search condition is met. The possible values are:\n\ \n\ AUSEARCH_STOP_EVENT:\n\ This one repositions the cursors to the first field of the first\n\ record of the event containing the items searched for.\n\ \n\ AUSEARCH_STOP_RECORD:\n\ This one repositions the cursors to the first field of the record\n\ containing the items searched for.\n\ \n\ AUSEARCH_STOP_FIELD:\n\ This one simply stops on the current field when the evaluation of the\n\ rules becomes true.\n\ \n\ No Return value, raises exception (ValueError) on error.\n\ "); static PyObject * AuParser_search_set_stop(AuParser *self, PyObject *args) { int where; int result; if (!PyArg_ParseTuple(args, "i", &where)) return NULL; PARSER_CHECK; result = ausearch_set_stop(self->au, where); if (result == 0) Py_RETURN_NONE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * ausearch_clear ********************************/ PyDoc_STRVAR(search_clear_doc, "search_clear() Clear search parameters.\n\ \n\ ausearch_clear clears any search parameters stored in the parser\n\ instance and frees memory associated with it.\n\ \n\ No Return value.\n\ "); static PyObject * AuParser_search_clear(AuParser *self) { PARSER_CHECK; ausearch_clear(self->au); Py_RETURN_NONE; } /******************************** * ausearch_next_event ********************************/ PyDoc_STRVAR(search_next_event_doc, "search_next_event() Find the next event that meets search criteria.\n\ \n\ search_next_event() will scan the input source and evaluate whether\n\ any record in an event contains the data being searched\n\ for. Evaluation is done at the record level.\n\ \n\ Returns True if a match was found\n\ Returns False if a match was not found.\n\ \n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_search_next_event(AuParser *self) { int result; PARSER_CHECK; result = ausearch_next_event(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_next_event ********************************/ PyDoc_STRVAR(parse_next_event_doc, "parse_next_event() Advance the parser to the next event.\n\ \n\ parse_next_event() will position the cursors at the first field of the first\n\ record of the next event in a file or buffer. It does not skip events\n\ or honor any search criteria that may be stored.\n\ \n\ Returns True if parser advances to next event.\n\ Returns False if there are no more events to parse\n\ \n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_parse_next_event(AuParser *self) { int result; PARSER_CHECK; result = auparse_next_event(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * aup_normalize ********************************/ PyDoc_STRVAR(aup_normalize_doc, "aup_normalize(opt) Normalize the audit event for uniform access to fields.\n\ \n\ aup_normalize() takes an argument to decide if it should also gather subject\n\ and object attributes. The possible values are:\n\ \n\ NORM_OPT_ALL:\n\ This means include subject and object attributes\n\ \n\ NORM_OPT_NO_ATTRS:\n\ This means do not gather subject and object attributes\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize(AuParser *self, PyObject *args) { int opt; int result; if (!PyArg_ParseTuple(args, "i", &opt)) return NULL; PARSER_CHECK; result = auparse_normalize(self->au, opt); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_get_event_kind ********************************/ PyDoc_STRVAR(aup_normalize_get_event_kind_doc, "aup_normalize_get_event_kind() This returns a string that indicates what\n\ kind of event this is.\n\ \n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_aup_normalize_get_event_kind(AuParser *self) { const char *kind = NULL; PARSER_CHECK; kind = auparse_normalize_get_event_kind(self->au); if (kind == NULL) { PyErr_SetString(PyExc_RuntimeError, "'event_kind' has no value"); return NULL; } return Py_BuildValue("s", kind); } /******************************** * aup_normalize_session ********************************/ PyDoc_STRVAR(aup_normalize_session_doc, "aup_normalize_session() This function positions the internal cursor on\n\ the session's field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_session(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_session(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_subject_primary ********************************/ PyDoc_STRVAR(aup_normalize_subject_primary_doc, "aup_normalize_subject_primary() This function positions the internal\n\ cursor on the subject's field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_subject_primary(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_subject_primary(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_subject_secondary ********************************/ PyDoc_STRVAR(aup_normalize_subject_secondary_doc, "aup_normalize_subject_secondary() This function positions the internal\n\ cursor on the subject's secondary field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_subject_secondary(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_subject_secondary(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_subject_first_attribute ********************************/ PyDoc_STRVAR(aup_normalize_subject_first_attribute_doc, "aup_normalize_subject_first_attribute() This function positions the internal\n\ cursor on the subject's first attribute field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_subject_first_attribute(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_subject_first_attribute(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_subject_next_attribute ********************************/ PyDoc_STRVAR(aup_normalize_subject_next_attribute_doc, "aup_normalize_subject_next_attribute() This function positions the internal\n\ cursor on the next subject's attribute field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_subject_next_attribute(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_subject_next_attribute(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_subject_kind ********************************/ PyDoc_STRVAR(aup_normalize_subject_kind_doc, "aup_normalize_subject_kind() This returns a string that indicates the\n\ kind of account the subject is.\n\ \n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_aup_normalize_subject_kind(AuParser *self) { const char *kind = NULL; PARSER_CHECK; kind = auparse_normalize_subject_kind(self->au); if (kind == NULL) { PyErr_SetString(PyExc_RuntimeError, "'subject_kind' has no value"); return NULL; } return Py_BuildValue("s", kind); } /******************************** * aup_normalize_get_action ********************************/ PyDoc_STRVAR(aup_normalize_get_action_doc, "aup_normalize_get_action() This returns a string that indicates the\n\ subject's action.\n\ \n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_aup_normalize_get_action(AuParser *self) { const char *action = NULL; PARSER_CHECK; action = auparse_normalize_get_action(self->au); if (action == NULL) { PyErr_SetString(PyExc_RuntimeError, "'action' has no value"); return NULL; } return Py_BuildValue("s", action); } /******************************** * aup_normalize_object_primary ********************************/ PyDoc_STRVAR(aup_normalize_object_primary_doc, "aup_normalize_object_primary() This function positions the internal\n\ cursor on the object's field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_object_primary(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_object_primary(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_object_secondary ********************************/ PyDoc_STRVAR(aup_normalize_object_secondary_doc, "aup_normalize_object_secondary() This function positions the internal\n\ cursor on the object's secondary field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_object_secondary(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_object_secondary(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_object_first_attribute ********************************/ PyDoc_STRVAR(aup_normalize_object_first_attribute_doc, "aup_normalize_object_first_attribute() This function positions the internal\n\ cursor on the object's first attribute field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_object_first_attribute(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_object_first_attribute(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_object_next_attribute ********************************/ PyDoc_STRVAR(aup_normalize_object_next_attribute_doc, "aup_normalize_object_next_attribute() This function positions the internal\n\ cursor on the next object's attribute field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_object_next_attribute(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_object_next_attribute(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_object_kind ********************************/ PyDoc_STRVAR(aup_normalize_object_kind_doc, "aup_normalize_object_kind() This returns a string that indicates the\n\ kind of thing the object is.\n\ \n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_aup_normalize_object_kind(AuParser *self) { const char *kind = NULL; PARSER_CHECK; kind = auparse_normalize_object_kind(self->au); if (kind == NULL) { PyErr_SetString(PyExc_RuntimeError, "'object_kind' has no value"); return NULL; } return Py_BuildValue("s", kind); } /******************************** * aup_normalize_get_results ********************************/ PyDoc_STRVAR(aup_normalize_get_results_doc, "aup_normalize_subject_primary() This function positions the internal\n\ cursor on the results field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_get_results(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_get_results(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * aup_normalize_how ********************************/ PyDoc_STRVAR(aup_normalize_how_doc, "aup_normalize_how() This returns a string that indicates the\n\ how the object is being accessed. This is usually a program.\n\ \n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_aup_normalize_how(AuParser *self) { const char *how = NULL; PARSER_CHECK; how = auparse_normalize_how(self->au); if (how == NULL) { PyErr_SetString(PyExc_RuntimeError, "'how' has no value"); return NULL; } return Py_BuildValue("s", how); } /******************************** * aup_normalize_key ********************************/ PyDoc_STRVAR(aup_normalize_key_doc, "aup_normalize_key() This function positions the internal\n\ cursor on the key field of the event.\n\ \n\ Returns True on success\n\ Returns False if uninitialized\n\ \n\ Raises exception (ValueError) on error\n\ "); static PyObject * AuParser_aup_normalize_key(AuParser *self) { int result; PARSER_CHECK; result = auparse_normalize_key(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_ValueError); return NULL; } /******************************** * auparse_get_timestamp ********************************/ PyDoc_STRVAR(get_timestamp_doc, "get_timestamp() Return current event's timestamp.\n\ \n\ Returns the current event's timestamp info as an AuEvent object.\n\ No Return value, raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_get_timestamp(AuParser *self) { const au_event_t *event_ptr; PyObject *py_event; PARSER_CHECK; event_ptr = auparse_get_timestamp(self->au); if (event_ptr == NULL) { if (errno) { PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } else { Py_RETURN_NONE; } } py_event = AuEvent_new_from_struct(event_ptr); return py_event; } /******************************** * auparse_get_num_records * ********************************/ PyDoc_STRVAR(get_num_records_doc, "get_num_records() Get the number of records.\n\ \n\ Returns the number of records in the current event.\n\ Raises exception (RuntimeError) on error.\n\ "); static PyObject * AuParser_get_num_records(AuParser *self) { int num_records; PARSER_CHECK; num_records = auparse_get_num_records(self->au); if (num_records == 0) { PyErr_SetString(PyExc_RuntimeError, "No records"); return NULL; } return Py_BuildValue("i", num_records); } /******************************** * auparse_first_record ********************************/ PyDoc_STRVAR(first_record_doc, "first_record() Reposition record cursor.\n\ \n\ first_record() repositions the internal cursors of the parsing library\n\ to point to the first record in the current event.\n\ \n\ Return True for success, False if there is no event data.\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_first_record(AuParser *self) { int result; PARSER_CHECK; result = auparse_first_record(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_next_record ********************************/ PyDoc_STRVAR(next_record_doc, "next_record() Advance record cursor.\n\ \n\ next_record() will move the internal library cursors to point to the\n\ next record of the current event.\n\ \n\ Returns True on success, False if no more records in current event\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_next_record(AuParser *self) { int result; PARSER_CHECK; result = auparse_next_record(self->au); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_get_record_num ********************************/ PyDoc_STRVAR(get_record_num_doc, "get_record_num() get one based record number where auparse is currently at\n\ The record numbering will reset back to 1 each time a new event is processed.\n\ Raises exception (RuntimeError) on error.\n\ "); static PyObject * AuParser_get_record_num(AuParser *self) { unsigned int value; PARSER_CHECK; value = auparse_get_record_num(self->au); if (value == 0) { PyErr_SetString(PyExc_RuntimeError, "No record number"); return NULL; } return Py_BuildValue("I", value); } /******************************** * auparse_goto_record_num ********************************/ PyDoc_STRVAR(goto_record_num_doc, "goto_record_num() Move record cursor to specific position.\n\ \n\ goto_record_num() will move the internal library cursors to point\n\ to a specific physical record number. Records within the same event are\n\ numbered starting from 0. This is generally not needed but there are\n\ some cases where one may want precise control over the exact record\n\ being looked at.\n\ \n\ Returns True on success, False if no more records in current event\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_goto_record_num(AuParser *self, PyObject *args) { int result; unsigned int num; if (!PyArg_ParseTuple(args, "i", &num)) return NULL; PARSER_CHECK; result = auparse_goto_record_num(self->au, num); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_get_type ********************************/ PyDoc_STRVAR(get_type_doc, "get_type() Get record’s type.\n\ \n\ get_type() will return the integer value for the current record of the\n\ current event.\n\ \n\ Returns record type.\n\ Raises exception (LookupError) on error.\n\ "); static PyObject * AuParser_get_type(AuParser *self) { int value; PARSER_CHECK; value = auparse_get_type(self->au); if (value == 0) { PyErr_SetString(PyExc_LookupError, "Not found"); return NULL; } return Py_BuildValue("i", value); } /******************************** * auparse_get_type_name ********************************/ PyDoc_STRVAR(get_type_name_doc, "get_type_name() Get current record’s type name.\n\ \n\ get_type_name() allows access to the current record type name in the\n\ current event.\n\ \n\ Raises exception (LookupError) on error.\n\ "); static PyObject * AuParser_get_type_name(AuParser *self) { const char *name = NULL; PARSER_CHECK; name = auparse_get_type_name(self->au); if (name == NULL) { PyErr_SetString(PyExc_LookupError, "Not found"); return NULL; } return Py_BuildValue("s", name); } /******************************** * auparse_get_line_number ********************************/ PyDoc_STRVAR(get_line_number_doc, "auparse_get_line_number() get line number where record was found\n\ \n\ get_line_number will return the source input line number for\n\ the current record of the current event. Line numbers start at 1. If\n\ the source input type is AUSOURCE_FILE_ARRAY the line numbering will\n\ reset back to 1 each time a new life in the file array is opened.\n\ Raises exception (RuntimeError) on error.\n\ "); static PyObject * AuParser_get_line_number(AuParser *self) { unsigned int value; PARSER_CHECK; value = auparse_get_line_number(self->au); if (value == 0) { PyErr_SetString(PyExc_RuntimeError, "No line number"); return NULL; } return Py_BuildValue("I", value); } /******************************** * auparse_get_filename ********************************/ PyDoc_STRVAR(get_filename_doc, "auparse_get_filename() get the filename where record was found\n\ get_filename() will return the name of the source file where the\n\ record was found if the source type is AUSOURCE_FILE or\n\ AUSOURCE_FILE_ARRAY. For other source types the return value will be\n\ None.\n\ "); static PyObject * AuParser_get_filename(AuParser *self) { const char *value; PARSER_CHECK; value = auparse_get_filename(self->au); if (value == NULL) Py_RETURN_NONE; return Py_BuildValue("s", value); } /******************************** * auparse_first_field ********************************/ PyDoc_STRVAR(first_field_doc, "first_field() Reposition field cursor.\n\ \n\ Returns True on success, False if there is no event data\n\ "); static PyObject * AuParser_first_field(AuParser *self) { int result; PARSER_CHECK; result = auparse_first_field(self->au); if (result == 0) Py_RETURN_FALSE; Py_RETURN_TRUE; } /******************************** * auparse_next_field ********************************/ PyDoc_STRVAR(next_field_doc, "next_field() Advance the field cursor.\n\ \n\ next_field() moves the library’s internal cursor to point to the next\n\ field in the current record of the current event.\n\ \n\ Returns True on success, False if there is no more fields exist\n\ "); static PyObject * AuParser_next_field(AuParser *self) { int result; PARSER_CHECK; result = auparse_next_field(self->au); if (result == 0) Py_RETURN_FALSE; Py_RETURN_TRUE; } /******************************** * auparse_get_num_fields ********************************/ PyDoc_STRVAR(get_num_fields_doc, "get_num_fields() Get the number of fields.\n\ \n\ Returns the number of fields in the current event.\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_get_num_fields(AuParser *self) { int num_fields; PARSER_CHECK; num_fields = auparse_get_num_fields(self->au); if (num_fields == 0) { PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } return Py_BuildValue("i", num_fields); } /******************************** * auparse_get_record_text ********************************/ PyDoc_STRVAR(get_record_text_doc, "get_record_text() Return unparsed record data\n\ \n\ get_record_text() returns the full unparsed record.\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_get_record_text(AuParser *self) { const char *text; PARSER_CHECK; text = auparse_get_record_text(self->au); if (text == NULL) { PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } return Py_BuildValue("s", text); } /******************************** * auparse_find_field ********************************/ PyDoc_STRVAR(find_field_doc, "find_field(name) Search for field name.\n\ \n\ find_field() will scan all records in an event to find the first\n\ occurrence of the field name passed to it. Searching begins from the\n\ cursor’s current position. The field name is stored for subsequent\n\ searching.\n\ \n\ Returns value associated with field or None if not found.\n\ "); static PyObject * AuParser_find_field(AuParser *self, PyObject *args) { char *name = NULL; const char *value; if (!PyArg_ParseTuple(args, "s:find_field", &name)) return NULL; PARSER_CHECK; if ((value =auparse_find_field(self->au, name)) == NULL) { if (errno) { PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } else { Py_RETURN_NONE; } } return Py_BuildValue("s", value); } /******************************** * auparse_find_field_next ********************************/ PyDoc_STRVAR(find_field_next_doc, "find_field_next() Get next occurrence of field name\n\ \n\ find_field_next() returns the value associated next occurrence of field name.\n\ Returns value associated with field or None if there is no next field.\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_find_field_next(AuParser *self) { const char *value; PARSER_CHECK; if ((value = auparse_find_field_next(self->au)) == NULL) { if (errno) { PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } else { Py_RETURN_NONE; } } return Py_BuildValue("s", value); } /******************************** * auparse_get_field_num ********************************/ PyDoc_STRVAR(get_field_num_doc, "get_field_num() get one based record number where auparse is currently at\n\ The record numbering will reset back to 1 each time a new event is processed.\n\ Raises exception (RuntimeError) on error.\n\ "); static PyObject * AuParser_get_field_num(AuParser *self) { unsigned int value; PARSER_CHECK; value = auparse_get_field_num(self->au); if (value == 0) { PyErr_SetString(PyExc_RuntimeError, "No field number"); return NULL; } return Py_BuildValue("I", value); } /******************************** * auparse_goto_field_num ********************************/ PyDoc_STRVAR(goto_field_num_doc, "goto_field_num() Move field cursor to specific position.\n\ \n\ goto_field_num() will move the internal library cursors to point\n\ to a specific physical field number. Fields within the same record are\n\ numbered starting from 1. This is generally not needed but there are\n\ some cases where one may want precise control over the exact field\n\ being looked at.\n\ \n\ Returns True on success, False if no more fields in current event\n\ Raises exception (EnvironmentError) on error.\n\ "); static PyObject * AuParser_goto_field_num(AuParser *self, PyObject *args) { int result; unsigned int num; if (!PyArg_ParseTuple(args, "i", &num)) return NULL; PARSER_CHECK; result = auparse_goto_field_num(self->au, num); if (result > 0) Py_RETURN_TRUE; if (result == 0) Py_RETURN_FALSE; PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } /******************************** * auparse_get_field_name ********************************/ PyDoc_STRVAR(get_field_name_doc, "get_field_name() Get current field’s name.\n\ \n\ get_field_name() allows access to the current field name of the\n\ current record in the current event.\n\ \n\ Returns None if the field value is unavailable.\n\ Returns String.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_get_field_name(AuParser *self) { const char *name = NULL; PARSER_CHECK; name = auparse_get_field_name(self->au); if (name == NULL) { PyErr_SetString(PyExc_RuntimeError, "'field name' is NULL"); return NULL; } return Py_BuildValue("s", name); } /******************************** * auparse_get_field_str ********************************/ PyDoc_STRVAR(get_field_str_doc, "get_field_str() get current field’s value\n\ \n\ get_field_str() allows access to the value in the current field of the\n\ current record in the current event.\n\ \n\ Returns String.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_get_field_str(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_get_field_str(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'field str' is NULL"); return NULL; } return Py_BuildValue("s", value); } /******************************** * auparse_get_field_type ********************************/ PyDoc_STRVAR(get_field_type_doc, "get_field_type() Get current field’s data type value.\n\ \n\ get_field_type() returns a value from the auparse_type_t enum that\n\ describes the kind of data in the current field of the current record\n\ in the current event.\n\ \n\ Returns AUPARSE_TYPE_UNCLASSIFIED if the field’s data type has no\n\ known description or is an integer. Otherwise it returns another enum.\n\ Fields with the type AUPARSE_TYPE_ESCAPED must be interpreted to access\n\ their value since those field’s raw value is encoded.\n\ "); static PyObject * AuParser_get_field_type(AuParser *self) { int value; PARSER_CHECK; value = auparse_get_field_type(self->au); return Py_BuildValue("i", value); } /******************************** * auparse_get_field_int ********************************/ PyDoc_STRVAR(get_field_int_doc, "get_field_int() Get current field’s value as an integer.\n\ \n\ get_field_int() allows access to the value as an int of the current\n\ field of the current record in the current event.\n\ \n\ Returns field's numeric value.\n\ Raises exception (EnvironmentError) on error\n\ "); static PyObject * AuParser_get_field_int(AuParser *self) { int value; PARSER_CHECK; value = auparse_get_field_int(self->au); if (errno == 0) return Py_BuildValue("i", value); PyErr_SetFromErrno(PyExc_EnvironmentError); return NULL; } PyDoc_STRVAR(interpret_field_doc, "interpret_field() Return an interpretation of the current field as a string that has the chosen character escaping applied.\n\ \n\ If the field cannot be interpreted the field is returned unmodified.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_interpret_field(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_interpret_field(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'interpretation' is NULL"); return NULL; } return Py_BuildValue("s", value); } PyDoc_STRVAR(interpret_realpath_doc, "interpret_realpath() Return an interpretation of the current field as a realpath string that has the chosen character escaping applied.\n\ \n\ If the field cannot be interpreted the field is returned unmodified.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_interpret_realpath(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_interpret_realpath(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'interpretation' is NULL"); return NULL; } return Py_BuildValue("s", value); } PyDoc_STRVAR(interpret_sock_family_doc, "interpret_sock_family() Return an interpretation of the current field's socket family. Only supported on sockaddr field types.\n\ \n\ If the field cannot be interpreted the field is returned unmodified.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_interpret_sock_family(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_interpret_sock_family(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'interpretation' is NULL"); return NULL; } return Py_BuildValue("s", value); } PyDoc_STRVAR(interpret_sock_port_doc, "interpret_sock_address() Return an interpretation of the current field's socket port. Only supported on sockaddr field types.\n\ \n\ If the field cannot be interpreted the field is returned unmodified.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_interpret_sock_port(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_interpret_sock_port(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'interpretation' is NULL"); return NULL; } return Py_BuildValue("s", value); } PyDoc_STRVAR(interpret_sock_address_doc, "interpret_sock_address() Return an interpretation of the current field's socket address. Only supported on sockaddr field types.\n\ \n\ If the field cannot be interpreted the field is returned unmodified.\n\ Raises exception (RuntimeError) on error\n\ "); static PyObject * AuParser_interpret_sock_address(AuParser *self) { const char *value = NULL; PARSER_CHECK; value = auparse_interpret_sock_address(self->au); if (value == NULL) { PyErr_SetString(PyExc_RuntimeError, "'interpretation' is NULL"); return NULL; } return Py_BuildValue("s", value); } static PyGetSetDef AuParser_getsetters[] = { {NULL} /* Sentinel */ }; static PyMemberDef AuParser_members[] = { {NULL} /* Sentinel */ }; static PyMethodDef AuParser_methods[] = { {"feed", (PyCFunction)AuParser_feed, METH_VARARGS, feed_doc}, {"flush_feed", (PyCFunction)AuParser_flush_feed, METH_NOARGS, flush_feed_doc}, {"feed_has_data", (PyCFunction)AuParser_feed_has_data, METH_NOARGS, feed_has_data_doc}, {"feed_has_ready_event", (PyCFunction)AuParser_feed_has_ready_event, METH_NOARGS, feed_has_ready_event_doc}, {"feed_age_events", (PyCFunction)AuParser_feed_age_events, METH_NOARGS, feed_age_events_doc}, {"add_callback", (PyCFunction)AuParser_add_callback, METH_VARARGS, add_callback_doc}, {"set_escape_mode", (PyCFunction)AuParser_set_escape_mode, METH_VARARGS, set_escape_mode_doc}, {"set_eoe_timeout", (PyCFunction)AuParser_set_eoe_timeout, METH_VARARGS, set_eoe_timeout_doc}, {"reset", (PyCFunction)AuParser_reset, METH_NOARGS, reset_doc}, {"metrics", (PyCFunction)AuParser_metrics, METH_NOARGS, metrics_doc}, {"search_add_expression", (PyCFunction)AuParser_search_add_expression, METH_VARARGS, search_add_expression_doc}, {"search_add_item", (PyCFunction)AuParser_search_add_item, METH_VARARGS, search_add_item_doc}, {"search_add_interpreted_item", (PyCFunction)AuParser_search_add_interpreted_item, METH_VARARGS, search_add_interpreted_item_doc}, {"search_add_timestamp_item", (PyCFunction)AuParser_search_add_timestamp_item, METH_VARARGS, search_add_timestamp_item_doc}, {"search_add_timestamp_item_ex", (PyCFunction)AuParser_search_add_timestamp_item_ex, METH_VARARGS, search_add_timestamp_item_ex_doc}, {"search_add_regex", (PyCFunction)AuParser_search_add_regex, METH_VARARGS, search_add_regex_doc}, {"search_set_stop", (PyCFunction)AuParser_search_set_stop, METH_VARARGS, search_set_stop_doc}, {"search_clear", (PyCFunction)AuParser_search_clear, METH_NOARGS, search_clear_doc}, {"search_next_event", (PyCFunction)AuParser_search_next_event, METH_NOARGS, search_next_event_doc}, {"parse_next_event", (PyCFunction)AuParser_parse_next_event, METH_NOARGS, parse_next_event_doc}, {"aup_normalize", (PyCFunction)AuParser_aup_normalize, METH_VARARGS, aup_normalize_doc}, {"aup_normalize_get_event_kind", (PyCFunction)AuParser_aup_normalize_get_event_kind, METH_NOARGS, aup_normalize_get_event_kind_doc}, {"aup_normalize_session", (PyCFunction)AuParser_aup_normalize_session, METH_NOARGS, aup_normalize_session_doc}, {"aup_normalize_subject_primary", (PyCFunction)AuParser_aup_normalize_subject_primary, METH_NOARGS, aup_normalize_subject_primary_doc}, {"aup_normalize_subject_secondary", (PyCFunction)AuParser_aup_normalize_subject_secondary, METH_NOARGS, aup_normalize_subject_secondary_doc}, {"aup_normalize_subject_first_attribute", (PyCFunction)AuParser_aup_normalize_subject_first_attribute, METH_NOARGS, aup_normalize_subject_first_attribute_doc}, {"aup_normalize_subject_next_attribute", (PyCFunction)AuParser_aup_normalize_subject_next_attribute, METH_NOARGS, aup_normalize_subject_next_attribute_doc}, {"aup_normalize_subject_kind", (PyCFunction)AuParser_aup_normalize_subject_kind, METH_NOARGS, aup_normalize_subject_kind_doc}, {"aup_normalize_get_action", (PyCFunction)AuParser_aup_normalize_get_action, METH_NOARGS, aup_normalize_get_action_doc}, {"aup_normalize_object_primary", (PyCFunction)AuParser_aup_normalize_object_primary, METH_NOARGS, aup_normalize_object_primary_doc}, {"aup_normalize_object_secondary", (PyCFunction)AuParser_aup_normalize_object_secondary, METH_NOARGS, aup_normalize_object_secondary_doc}, {"aup_normalize_object_first_attribute", (PyCFunction)AuParser_aup_normalize_object_first_attribute, METH_NOARGS, aup_normalize_object_first_attribute_doc}, {"aup_normalize_object_next_attribute", (PyCFunction)AuParser_aup_normalize_object_next_attribute, METH_NOARGS, aup_normalize_object_next_attribute_doc}, {"aup_normalize_object_kind", (PyCFunction)AuParser_aup_normalize_object_kind, METH_NOARGS, aup_normalize_object_kind_doc}, {"aup_normalize_get_results", (PyCFunction)AuParser_aup_normalize_get_results, METH_NOARGS, aup_normalize_get_results_doc}, {"aup_normalize_how", (PyCFunction)AuParser_aup_normalize_how, METH_NOARGS, aup_normalize_how_doc}, {"aup_normalize_key", (PyCFunction)AuParser_aup_normalize_key, METH_NOARGS, aup_normalize_key_doc}, {"get_timestamp", (PyCFunction)AuParser_get_timestamp, METH_NOARGS, get_timestamp_doc}, {"get_num_records", (PyCFunction)AuParser_get_num_records, METH_NOARGS, get_num_records_doc}, {"first_record", (PyCFunction)AuParser_first_record, METH_NOARGS, first_record_doc}, {"next_record", (PyCFunction)AuParser_next_record, METH_NOARGS, next_record_doc}, {"get_record_num", (PyCFunction)AuParser_get_record_num, METH_NOARGS, get_record_num_doc}, {"goto_record_num", (PyCFunction)AuParser_goto_record_num, METH_VARARGS, goto_record_num_doc}, {"get_type", (PyCFunction)AuParser_get_type, METH_NOARGS, get_type_doc}, {"get_type_name", (PyCFunction)AuParser_get_type_name, METH_NOARGS, get_type_name_doc}, {"get_line_number", (PyCFunction)AuParser_get_line_number, METH_NOARGS, get_line_number_doc}, {"get_filename", (PyCFunction)AuParser_get_filename, METH_NOARGS, get_filename_doc}, {"first_field", (PyCFunction)AuParser_first_field, METH_NOARGS, first_field_doc}, {"next_field", (PyCFunction)AuParser_next_field, METH_NOARGS, next_field_doc}, {"get_num_fields", (PyCFunction)AuParser_get_num_fields, METH_NOARGS, get_num_fields_doc}, {"get_record_text", (PyCFunction)AuParser_get_record_text, METH_NOARGS, get_record_text_doc}, {"find_field_next", (PyCFunction)AuParser_find_field_next, METH_NOARGS, find_field_next_doc}, {"get_field_num", (PyCFunction)AuParser_get_field_num, METH_NOARGS, get_field_num_doc}, {"goto_field_num", (PyCFunction)AuParser_goto_field_num, METH_VARARGS, goto_field_num_doc}, {"find_field", (PyCFunction)AuParser_find_field, METH_VARARGS, find_field_doc}, {"get_field_name", (PyCFunction)AuParser_get_field_name, METH_NOARGS, get_field_name_doc}, {"get_field_str", (PyCFunction)AuParser_get_field_str, METH_NOARGS, get_field_str_doc}, {"get_field_type", (PyCFunction)AuParser_get_field_type, METH_NOARGS, get_field_type_doc}, {"get_field_int", (PyCFunction)AuParser_get_field_int, METH_NOARGS, get_field_int_doc}, {"interpret_field", (PyCFunction)AuParser_interpret_field, METH_NOARGS, interpret_field_doc}, {"interpret_realpath", (PyCFunction)AuParser_interpret_realpath, METH_NOARGS, interpret_realpath_doc}, {"interpret_sock_family", (PyCFunction)AuParser_interpret_sock_family, METH_NOARGS, interpret_sock_family_doc}, {"interpret_sock_port", (PyCFunction)AuParser_interpret_sock_port, METH_NOARGS, interpret_sock_port_doc}, {"interpret_sock_address", (PyCFunction)AuParser_interpret_sock_address, METH_NOARGS, interpret_sock_address_doc}, {NULL, NULL, 0, NULL} /* Sentinel */ }; PyDoc_STRVAR(AuParser_doc, "AuParser(source_type, source)\n\ \n\ Construct a new audit parser object and bind it to input data.\n\ source_type: one of the AUSOURCE_* constants.\n\ source: the input data, dependent on the source_type as follows:\n\ \n\ AUSOURCE_LOGS: None (system log files will be parsed)\n\ AUSOURCE_FILE: string containing file path name\n\ AUSOURCE_FILE_ARRAY: list or tuple of strings each containing a file path name\n\ AUSOURCE_BUFFER: string containing audit data to parse\n\ AUSOURCE_BUFFER_ARRAY: list or tuple of strings each containing audit data to parse\n\ AUSOURCE_DESCRIPTOR: integer file descriptor (e.g. fileno)\n\ AUSOURCE_FILE_POINTER: file object (e.g. types.FileType)\n\ AUSOURCE_FEED: None (data supplied via feed()\n\ "); static PyTypeObject AuParserType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "auparse.AuParser", .tp_basicsize = sizeof(AuParser), .tp_dealloc = (destructor)AuParser_dealloc, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_doc = AuParser_doc, .tp_methods = AuParser_methods, .tp_members = AuParser_members, .tp_getset = AuParser_getsetters, .tp_init = (initproc)AuParser_init, .tp_new = AuParser_new, }; /*=========================================================================== * Module *===========================================================================*/ static PyMethodDef module_methods[] = { {NULL} /* Sentinel */ }; static struct PyModuleDef auparse_def = { PyModuleDef_HEAD_INIT, "auparse", NULL, -1, module_methods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_auparse(void) { PyObject* m; if (PyType_Ready(&AuEventType) < 0) MODINITERROR; if (PyType_Ready(&AuParserType) < 0) MODINITERROR; m = PyModule_Create(&auparse_def); if (m == NULL) MODINITERROR; Py_INCREF(&AuParserType); PyModule_AddObject(m, "AuParser", (PyObject *)&AuParserType); Py_INCREF(&AuEventType); PyModule_AddObject(m, "AuEvent", (PyObject *)&AuEventType); /* exceptions */ NoParserError = PyErr_NewException("auparse.NoParser", NULL, NULL); Py_INCREF(NoParserError); PyModule_AddObject(m, "NoParser", NoParserError); /* ausource_t */ PyModule_AddIntConstant(m, "AUSOURCE_LOGS", AUSOURCE_LOGS); PyModule_AddIntConstant(m, "AUSOURCE_FILE", AUSOURCE_FILE); PyModule_AddIntConstant(m, "AUSOURCE_FILE_ARRAY", AUSOURCE_FILE_ARRAY); PyModule_AddIntConstant(m, "AUSOURCE_BUFFER", AUSOURCE_BUFFER); PyModule_AddIntConstant(m, "AUSOURCE_BUFFER_ARRAY", AUSOURCE_BUFFER_ARRAY); PyModule_AddIntConstant(m, "AUSOURCE_DESCRIPTOR", AUSOURCE_DESCRIPTOR); PyModule_AddIntConstant(m, "AUSOURCE_FILE_POINTER", AUSOURCE_FILE_POINTER); PyModule_AddIntConstant(m, "AUSOURCE_FEED", AUSOURCE_FEED); /* ausearch_op_t */ PyModule_AddIntConstant(m, "AUSEARCH_UNSET", AUSEARCH_UNSET); PyModule_AddIntConstant(m, "AUSEARCH_EXISTS", AUSEARCH_EXISTS); PyModule_AddIntConstant(m, "AUSEARCH_EQUAL", AUSEARCH_EQUAL); PyModule_AddIntConstant(m, "AUSEARCH_NOT_EQUAL", AUSEARCH_NOT_EQUAL); PyModule_AddIntConstant(m, "AUSEARCH_TIME_LT", AUSEARCH_TIME_LT); PyModule_AddIntConstant(m, "AUSEARCH_TIME_LE", AUSEARCH_TIME_LE); PyModule_AddIntConstant(m, "AUSEARCH_TIME_GE", AUSEARCH_TIME_GE); PyModule_AddIntConstant(m, "AUSEARCH_TIME_GT", AUSEARCH_TIME_GT); PyModule_AddIntConstant(m, "AUSEARCH_TIME_EQ", AUSEARCH_TIME_EQ); PyModule_AddIntConstant(m, "AUSEARCH_INTERPRETED", 0x40000000); /* austop_t */ PyModule_AddIntConstant(m, "AUSEARCH_STOP_EVENT", AUSEARCH_STOP_EVENT); PyModule_AddIntConstant(m, "AUSEARCH_STOP_RECORD", AUSEARCH_STOP_RECORD); PyModule_AddIntConstant(m, "AUSEARCH_STOP_FIELD", AUSEARCH_STOP_FIELD); /* normalize_option_t */ PyModule_AddIntConstant(m, "NORM_OPT_ALL", NORM_OPT_ALL); PyModule_AddIntConstant(m, "NORM_OPT_NO_ATTRS", NORM_OPT_NO_ATTRS); /* ausearch_rule_t */ PyModule_AddIntConstant(m, "AUSEARCH_RULE_CLEAR", AUSEARCH_RULE_CLEAR); PyModule_AddIntConstant(m, "AUSEARCH_RULE_OR", AUSEARCH_RULE_OR); PyModule_AddIntConstant(m, "AUSEARCH_RULE_AND", AUSEARCH_RULE_AND); PyModule_AddIntConstant(m, "AUSEARCH_RULE_REGEX", AUSEARCH_RULE_REGEX); /* auparse_cb_event_t */ PyModule_AddIntConstant(m, "AUPARSE_CB_EVENT_READY", AUPARSE_CB_EVENT_READY); /* auparse_type_t */ PyModule_AddIntConstant(m, "AUPARSE_TYPE_UNCLASSIFIED", AUPARSE_TYPE_UNCLASSIFIED); PyModule_AddIntConstant(m, "AUPARSE_TYPE_UID", AUPARSE_TYPE_UID); PyModule_AddIntConstant(m, "AUPARSE_TYPE_GID", AUPARSE_TYPE_GID); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SYSCALL", AUPARSE_TYPE_SYSCALL); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ARCH", AUPARSE_TYPE_ARCH); PyModule_AddIntConstant(m, "AUPARSE_TYPE_EXIT", AUPARSE_TYPE_EXIT); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ESCAPED", AUPARSE_TYPE_ESCAPED); PyModule_AddIntConstant(m, "AUPARSE_TYPE_PERM", AUPARSE_TYPE_PERM); PyModule_AddIntConstant(m, "AUPARSE_TYPE_MODE", AUPARSE_TYPE_MODE); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SOCKADDR", AUPARSE_TYPE_SOCKADDR); PyModule_AddIntConstant(m, "AUPARSE_TYPE_FLAGS", AUPARSE_TYPE_FLAGS); PyModule_AddIntConstant(m, "AUPARSE_TYPE_PROMISC", AUPARSE_TYPE_PROMISC); PyModule_AddIntConstant(m, "AUPARSE_TYPE_CAPABILITY", AUPARSE_TYPE_CAPABILITY); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SUCCESS", AUPARSE_TYPE_SUCCESS); PyModule_AddIntConstant(m, "AUPARSE_TYPE_A0", AUPARSE_TYPE_A0); PyModule_AddIntConstant(m, "AUPARSE_TYPE_A1", AUPARSE_TYPE_A1); PyModule_AddIntConstant(m, "AUPARSE_TYPE_A2", AUPARSE_TYPE_A2); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SIGNAL", AUPARSE_TYPE_SIGNAL); PyModule_AddIntConstant(m, "AUPARSE_TYPE_LIST", AUPARSE_TYPE_LIST); PyModule_AddIntConstant(m, "AUPARSE_TYPE_TTY_DATA", AUPARSE_TYPE_TTY_DATA); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SESSION", AUPARSE_TYPE_SESSION); PyModule_AddIntConstant(m, "AUPARSE_TYPE_CAP_BITMAP", AUPARSE_TYPE_CAP_BITMAP); PyModule_AddIntConstant(m, "AUPARSE_TYPE_NFPROTO", AUPARSE_TYPE_NFPROTO); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ICMPTYPE", AUPARSE_TYPE_ICMPTYPE); PyModule_AddIntConstant(m, "AUPARSE_TYPE_PROTOCOL", AUPARSE_TYPE_PROTOCOL); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ADDR", AUPARSE_TYPE_ADDR); PyModule_AddIntConstant(m, "AUPARSE_TYPE_PERSONALITY", AUPARSE_TYPE_PERSONALITY); PyModule_AddIntConstant(m, "AUPARSE_TYPE_SECCOMP", AUPARSE_TYPE_SECCOMP); PyModule_AddIntConstant(m, "AUPARSE_TYPE_OFLAG", AUPARSE_TYPE_OFLAG); PyModule_AddIntConstant(m, "AUPARSE_TYPE_MMAP", AUPARSE_TYPE_MMAP); PyModule_AddIntConstant(m, "AUPARSE_TYPE_MODE_SHORT", AUPARSE_TYPE_MODE_SHORT); PyModule_AddIntConstant(m, "AUPARSE_TYPE_MAC_LABEL", AUPARSE_TYPE_MAC_LABEL); PyModule_AddIntConstant(m, "AUPARSE_TYPE_PROCTITLE", AUPARSE_TYPE_PROCTITLE); PyModule_AddIntConstant(m, "AUPARSE_TYPE_HOOK", AUPARSE_TYPE_HOOK); PyModule_AddIntConstant(m, "AUPARSE_TYPE_NETACTION", AUPARSE_TYPE_NETACTION); PyModule_AddIntConstant(m, "AUPARSE_TYPE_MACPROTO,", AUPARSE_TYPE_MACPROTO); PyModule_AddIntConstant(m, "AUPARSE_TYPE_IOCTL_REQ", AUPARSE_TYPE_IOCTL_REQ); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ESCAPED_KEY", AUPARSE_TYPE_ESCAPED_KEY); PyModule_AddIntConstant(m, "AUPARSE_TYPE_ESCAPED_FILE", AUPARSE_TYPE_ESCAPED_FILE); PyModule_AddIntConstant(m, "AUPARSE_TYPE_FANOTIFY", AUPARSE_TYPE_FANOTIFY); PyModule_AddIntConstant(m, "AUPARSE_TYPE_NLMCGRP", AUPARSE_TYPE_NLMCGRP); PyModule_AddIntConstant(m, "AUPARSE_TYPE_RESOLVE", AUPARSE_TYPE_RESOLVE); /* Escape types */ PyModule_AddIntConstant(m, "AUPARSE_ESC_RAW", AUPARSE_ESC_RAW); PyModule_AddIntConstant(m, "AUPARSE_ESC_TTY", AUPARSE_ESC_TTY); PyModule_AddIntConstant(m, "AUPARSE_ESC_SHELL", AUPARSE_ESC_SHELL); PyModule_AddIntConstant(m, "AUPARSE_ESC_SHELL_QUOTE", AUPARSE_ESC_SHELL_QUOTE); return m; } audit-userspace-4.0.5/bindings/python/python3/000077500000000000000000000000001501761310600213405ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/python/python3/Makefile.am000066400000000000000000000027031501761310600233760ustar00rootroot00000000000000# Makefile.am -- # Copyright 2015,2024 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig AM_CFLAGS = -fPIC -DPIC -fno-strict-aliasing $(PYTHON3_CFLAGS) AM_CPPFLAGS = -I$(top_builddir) $(PYTHON3_INCLUDES) pyexec_LTLIBRARIES = auparse.la auparse_la_SOURCES = $(top_srcdir)/bindings/python/auparse_python.c auparse_la_CPPFLAGS = -I$(top_srcdir)/auparse $(AM_CPPFLAGS) auparse_la_CFLAGS = -shared auparse_la_LDFLAGS = -module -avoid-version -Wl,-z,relro auparse_la_LIBADD = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la auparse_la_DEPENDENCIES = ${top_builddir}/auparse/libauparse.la ${top_builddir}/lib/libaudit.la audit-userspace-4.0.5/bindings/swig/000077500000000000000000000000001501761310600173645ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/swig/Makefile.am000066400000000000000000000017551501761310600214300ustar00rootroot00000000000000# Makefile.am -- # Copyright 2023 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = src/auditswig.i SUBDIRS = src if USE_PYTHON3 SUBDIRS += python3 endif audit-userspace-4.0.5/bindings/swig/python3/000077500000000000000000000000001501761310600207705ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/swig/python3/Makefile.am000066400000000000000000000033171501761310600230300ustar00rootroot00000000000000# Makefile.am -- # Copyright 2015 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig AM_CFLAGS = -fPIC -DPIC -fno-strict-aliasing $(PYTHON3_CFLAGS) AM_CPPFLAGS = -I. -I$(top_builddir) -I${top_srcdir}/lib $(PYTHON3_INCLUDES) LIBS = $(top_builddir)/lib/libaudit.la SWIG_FLAGS = -python SWIG_INCLUDES = -I. -I$(top_builddir) -I${top_srcdir}/lib $(PYTHON3_INCLUDES) pyexec_PYTHON = audit.py pyexec_LTLIBRARIES = _audit.la _audit_la_CFLAGS = -shared _audit_la_LDFLAGS = -module -avoid-version -Wl,-z,relro _audit_la_HEADERS: $(top_builddir)/config.h _audit_la_DEPENDENCIES =${top_srcdir}/lib/audit_logging.h ${top_builddir}/lib/libaudit.la _audit_la_LIBADD = ${top_builddir}/lib/libaudit.la nodist__audit_la_SOURCES = audit_wrap.c audit.py audit_wrap.c: ${srcdir}/../src/auditswig.i swig -o audit_wrap.c ${SWIG_FLAGS} ${SWIG_INCLUDES} ${srcdir}/../src/auditswig.i CLEANFILES = audit.py* audit_wrap.c *~ audit-userspace-4.0.5/bindings/swig/src/000077500000000000000000000000001501761310600201535ustar00rootroot00000000000000audit-userspace-4.0.5/bindings/swig/src/Makefile.am000066400000000000000000000017151501761310600222130ustar00rootroot00000000000000# Makefile.am -- # Copyright 2015 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # EXTRA_DIST = auditswig.i SWIG_SOURCES = auditswig.i CONFIG_CLEAN_FILES = *.loT *.rej *.orig audit-userspace-4.0.5/bindings/swig/src/auditswig.i000066400000000000000000000044541501761310600223340ustar00rootroot00000000000000/* Author: Dan Walsh * * Copyright (C) 2005,2006,2009,2023 Red Hat * * 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 audit %{ #include "../lib/audit_logging.h" // Have to declare these so they can be wrapped later extern int audit_set_enabled(int fd, uint32_t enabled); extern int audit_is_enabled(int fd); extern int audit_elf_to_machine(unsigned int elf); extern const char *audit_machine_to_name(int machine); extern const char *audit_syscall_to_name(int sc, int machine); extern int audit_detect_machine(void); extern const char *audit_msg_type_to_name(int msg_type); %} #if defined(SWIGPYTHON) %exception audit_open { $action if (result < 0) { PyErr_SetFromErrno(PyExc_OSError); return NULL; } } #endif %define __signed__ signed %enddef #define __attribute(X) /*nothing*/ typedef unsigned __u32; typedef unsigned uid_t; /* Sidestep SWIG's limitation of handling c99 Flexible arrays by not: * generating setters against them: https://github.com/swig/swig/issues/1699 */ %ignore audit_rule_data::buf; %include "/usr/include/linux/audit.h" #define __extension__ /*nothing*/ %include %include "../lib/audit-records.h" %include "../lib/audit_logging.h" /* * These are provided especially for setroubleshooter support */ int audit_elf_to_machine(unsigned int elf); const char *audit_machine_to_name(int machine); const char *audit_syscall_to_name(int sc, int machine); int audit_detect_machine(void); const char *audit_msg_type_to_name(int msg_type); /* * These are provided for simple check and set ops */ int audit_set_enabled(int fd, uint32_t enabled); int audit_is_enabled(int fd); audit-userspace-4.0.5/common/000077500000000000000000000000001501761310600161065ustar00rootroot00000000000000audit-userspace-4.0.5/common/Makefile.am000066400000000000000000000021561501761310600201460ustar00rootroot00000000000000# Makefile.am-- # Copyright 2018-2025 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig AM_CFLAGS = -fPIC -DPIC -D_GNU_SOURCE -g AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib noinst_HEADERS = common.h libaucommon_la_DEPENDENCIES = ../config.h libaucommon_la_SOURCES = strsplit.c common.c noinst_LTLIBRARIES = libaucommon.la audit-userspace-4.0.5/common/common.c000066400000000000000000000100531501761310600175410ustar00rootroot00000000000000/* common.c -- * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "libaudit.h" #include "common.h" #include #include #include #include #include #include // strtol #include /* * This function returns 1 if it is the last record in an event. * It returns 0 otherwise. * * When processing an event stream we define the end of an event via * record type = AUDIT_EOE (audit end of event type record), or * record type = AUDIT_PROCTITLE (we note the AUDIT_PROCTITLE is always * the last record), or * record type = AUDIT_KERNEL (kernel events are one record events), or * record type < AUDIT_FIRST_EVENT (only single record events appear * before this type), or * record type >= AUDIT_FIRST_ANOM_MSG (only single record events appear * after this type), or * record type >= AUDIT_MAC_UNLBL_ALLOW && record type <= AUDIT_MAC_CALIPSO_DEL * (these are also one record events) */ int audit_is_last_record(int type) { if (type == AUDIT_PROCTITLE || type == AUDIT_EOE || (type > AUDIT_LOGIN && type < AUDIT_FIRST_EVENT) || type == AUDIT_USER || type >= AUDIT_FIRST_ANOM_MSG || type == AUDIT_KERNEL || (type >= AUDIT_MAC_UNLBL_ALLOW && type <= AUDIT_MAC_CALIPSO_DEL)) { return 1; } return 0; } int write_to_console(const char *fmt, ...) { int fd; int res = 1; va_list args; if ((fd = open("/dev/console", O_WRONLY)) < 0) return 0; va_start(args, fmt); if (vdprintf(fd, fmt, args) < 0) { res = 0; } va_end(args); close(fd); return res; } void wall_message(const char* format, ...) { struct utmpx* entry; char message[512]; va_list args; int fd; // Format the message va_start(args, format); vsnprintf(message, sizeof(message), format, args); va_end(args); setutxent(); // Send the message to all active users while ((entry = getutxent())) { // Only active users have a valid terminal if (entry->ut_type == USER_PROCESS) { char tty_path[128]; snprintf(tty_path, sizeof(tty_path), "/dev/%s", entry->ut_line); fd = open(tty_path, O_WRONLY | O_NOCTTY); if (fd != -1) { dprintf(fd, "\nBroadcast message from audit daemon:\n%s\n", message); close(fd); } } } endutxent(); } // Returns converted time in seconds on success and -1 on failure. long time_string_to_seconds(const char *time_string, const char *subsystem, int line) { char *end; long i; errno = 0; i = strtol(time_string, &end, 10); if (errno || time_string == end) { if (subsystem) syslog(LOG_ERR, "%s: Error converting %s to a number - line %d", subsystem, time_string, line); return -1; } if (*end && end[1]) { if (subsystem) syslog(LOG_ERR, "%s: Unexpected characters in %s - line %d", subsystem, time_string, line); return -1; } switch (*end) { case 'm': i *= MINUTES; break; case 'h': i *= HOURS; break; case 'd': i *= DAYS; break; case 'M': i *= MONTHS; break; case '\0': break; default: if (subsystem) syslog(LOG_ERR, "%s: Unknown time unit in %s - line %d", subsystem, time_string, line); return -1; } return i; } audit-userspace-4.0.5/common/common.h000066400000000000000000000053351501761310600175550ustar00rootroot00000000000000/* common.h -- common utility functions used throughout * Copyright 2018-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef AUDIT_COMMON_HEADER #define AUDIT_COMMON_HEADER #ifdef HAVE_ATOMIC #include #endif #include #include "dso.h" // These macros originate in sys/cdefs.h #ifndef __attr_access # define __attr_access(x) #endif #ifndef __attribute_malloc__ # define __attribute_malloc__ #endif #ifndef __attr_dealloc # define __attr_dealloc(dealloc, argno) #endif #ifndef __wur # define __wur #endif /* Wrapper macros for optional atomics * Note: ATOMIC_INT and ATOMIC_UNSIGNED are defined in config.h */ #ifdef HAVE_ATOMIC # define AUDIT_ATOMIC_STORE(var, val) \ atomic_store_explicit(&(var), (val), memory_order_relaxed) # define AUDIT_ATOMIC_LOAD(var) \ atomic_load_explicit(&(var), memory_order_relaxed) #else # define AUDIT_ATOMIC_STORE(var, val) do { (var) = (val); } while (0) # define AUDIT_ATOMIC_LOAD(var) (var) #endif // Used in auditd-event.c and audisp.c to size buffers for formatting #define FORMAT_BUF_LEN (MAX_AUDIT_MESSAGE_LENGTH + _POSIX_HOST_NAME_MAX) AUDIT_HIDDEN_START char *audit_strsplit_r(char *s, char **savedpp); char *audit_strsplit(char *s); int audit_is_last_record(int type); #define MINUTES 60 #define HOURS 60*MINUTES #define DAYS 24*HOURS #define WEEKS 7*DAYS #define MONTHS 30*DAYS long time_string_to_seconds(const char *time_string, const char *subsystem, int line); int write_to_console(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))); #else ; #endif void wall_message(const char *fmt, ...) #ifdef __GNUC__ __attribute__((format(printf, 1, 2))); #else ; #endif AUDIT_HIDDEN_END // FIXME temporary /* Helper function for reading stdin in plugins */ void audit_fgets_clear(void); int audit_fgets_eof(void); int audit_fgets_more(size_t blen); int audit_fgets(char *buf, size_t blen, int fd) __attr_access ((__write_only__, 1, 2)); #endif audit-userspace-4.0.5/common/strsplit.c000066400000000000000000000035471501761310600201470ustar00rootroot00000000000000/* strsplit.c -- * Copyright 2014,2016,2017,2025 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include "common.h" #pragma GCC optimize("O3") /* * This function is similar to strtok_r except it is aimed at * splitting strings at a space character. */ char *audit_strsplit_r(char *s, char **savedpp) { char *ptr; // On new string, initialize if (s) *savedpp = s; // Are we done? if (*savedpp == NULL) return NULL; // skip leading spaces while (**savedpp == ' ') (*savedpp)++; // end of string? if (**savedpp == '\0') { *savedpp = NULL; return NULL; } // Mark the start ptr = *savedpp; // advance until space or end while (**savedpp != '\0' && **savedpp != ' ') (*savedpp)++; if (**savedpp == ' ') *(*savedpp)++ = '\0'; // terminate and advance past the space else *savedpp = NULL; // at end of string return ptr; } /* * This function is similar to strtok except it is aimed at * splitting strings at a space character. */ char *audit_strsplit(char *s) { static char *str; return audit_strsplit_r(s, &str); } audit-userspace-4.0.5/configure.ac000066400000000000000000000354611501761310600171150ustar00rootroot00000000000000dnl define([AC_INIT_NOTICE], [### Generated automatically using autoconf version] AC_ACVERSION [ ### Copyright 2005-25 Steve Grubb ### ### Permission is hereby granted, free of charge, to any person obtaining a ### copy of this software and associated documentation files (the "Software"), ### to deal in the Software without restriction, including without limitation ### the rights to use, copy, modify, merge, publish, distribute, sublicense, ### and/or sell copies of the Software, and to permit persons to whom the ### Software is furnished to do so, subject to the following conditions: ### ### The above copyright notice and this permission notice shall be included ### in all copies or substantial portions of the Software. ### ### THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ### IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ### FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ### THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ### OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ### ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ### OTHER DEALINGS IN THE SOFTWARE. ### ### For usage, run `./configure --help' ### For more detailed information on installation, read the file `INSTALL'. ### ### If configuration succeeds, status is in the file `config.status'. ### A log of configuration tests is in `config.log'. ]) AC_REVISION($Revision: 1.3 $)dnl AC_INIT([audit], [4.0.5]) AC_PREREQ([2.50])dnl AC_CONFIG_HEADERS([config.h]) echo Configuring auditd $VERSION AC_CONFIG_MACRO_DIR([m4]) AC_CANONICAL_TARGET AM_INIT_AUTOMAKE([subdir-objects foreign]) LT_INIT AC_SUBST(LIBTOOL_DEPS) OLDLIBS="$LIBS" m4_include([src/libev/libev.m4]) libev_LIBS="$LIBS" LIBS="$OLDLIBS" echo . echo Checking for programs AC_PROG_CC AC_PROG_INSTALL AC_PROG_AWK AX_PROG_CC_FOR_BUILD echo . echo Checking for header files AC_CHECK_SIZEOF([unsigned int]) AC_CHECK_SIZEOF([unsigned long]) AC_CHECK_SIZEOF([long]) AC_CHECK_SIZEOF([time_t]) dnl; next is needed for old compilers and plugins/ids/Makefile.am AM_PROG_CC_C_O AC_CHECK_DECLS([AUDIT_FEATURE_VERSION], [], [], [[#include ]]) AC_CHECK_MEMBERS([struct audit_status.feature_bitmap], [], [], [[#include ]]) AC_CHECK_DECLS([AUDIT_VERSION_BACKLOG_WAIT_TIME], [], [], [[#include ]]) AC_CHECK_DECLS([AUDIT_STATUS_BACKLOG_WAIT_TIME], [], [], [[#include ]]) AC_CHECK_DECLS([AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL], [], [], [[#include ]]) AC_CHECK_DECLS([ADDR_NO_RANDOMIZE],,, [#include ]) dnl; posix_fallocate is used in audisp-remote AC_CHECK_FUNCS([posix_fallocate]) dnl; signalfd is needed for libev AC_CHECK_FUNC([signalfd], [], [ AC_MSG_ERROR([The signalfd system call is necessary for auditd]) ]) dnl; check if rawmemchr is available AC_CHECK_FUNCS([rawmemchr]) dnl; check if faccessat is available AC_CHECK_FUNCS([faccessat]) dnl; check if mallinfo2 is available AC_CHECK_FUNCS([mallinfo2]) dnl; check if close_range is available AC_CHECK_FUNCS([close_range]) dnl; check if strndupa is available AC_LINK_IFELSE( [AC_LANG_SOURCE( [[ #define _GNU_SOURCE #include int main() { (void) strndupa("test", 10); return 0; }]])], [AC_DEFINE(HAVE_STRNDUPA, 1, [Let us know if we have it or not])], [] ) AC_CHECK_HEADERS([stdatomic.h], [ AC_DEFINE([HAVE_ATOMIC], 1, [Define to 1 if you have the header file.]) AC_DEFINE([ATOMIC_INT], atomic_int, [Define atomic_int if you have the header file.]) AC_DEFINE([ATOMIC_UNSIGNED], atomic_uint, [Define atomic_uint if you have the header file.]) ], [ AC_DEFINE([ATOMIC_INT], int, [Define to the type of an int if is not available.]) AC_DEFINE([ATOMIC_UNSIGNED], unsigned, [Define to the type of an unsigned if is not available.]) ]) AC_MSG_CHECKING(__attr_access support) AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[ #include int audit_fgets(char *buf, size_t blen, int fd) __attr_access ((__write_only__, 1, 2)); int main(void) { return 0; }]])], [ACCESS="yes"], [ACCESS="no"] ) AC_MSG_RESULT($ACCESS) AC_MSG_CHECKING(__attr_dealloc_free support) AC_COMPILE_IFELSE( [AC_LANG_SOURCE( [[ #include extern char *audit_encode_nv_string(const char *name, const char *value, unsigned int vlen) __attr_dealloc_free; int main(void) { return 0; }]])], [DEALLOC="yes"], [DEALLOC="no"] ) AC_MSG_RESULT($DEALLOC) dnl; pthread_yield is used in zos-remote OLDLIBS="$LIBS" AC_SEARCH_LIBS(pthread_yield, pthread, [AC_DEFINE(HAVE_PTHREAD_YIELD, 1, [Define to 1 if we have pthread_yield])], []) LIBS="$OLDLIBS" withval="" AC_MSG_CHECKING(whether to create python3 bindings) AC_ARG_WITH(python3, AS_HELP_STRING([--with-python3],[enable building python3 bindings]), use_python3=$withval, use_python3=auto) if test "x$use_python3" = xno ; then AC_MSG_RESULT(no) else AC_MSG_RESULT(investigating) AC_PATH_PROG([use_python3], [python3-config], [no]) if test "x$use_python3" = xno ; then if test "x$withval" = xyes ; then echo "Python3 bindings were selected but python3-config was not found." echo "Please ensure that it's installed or pass --without-python3 to ./configure" exit 1 fi echo "Python3 bindings will NOT be built" else echo "Python3 bindings WILL be built" use_python3=yes AM_PATH_PYTHON([3.1],, [:]) PYTHON3_CFLAGS=`python3-config --cflags 2> /dev/null` PYTHON3_LIBS=`python3-config --libs 2> /dev/null` PYTHON3_INCLUDES=`python3-config --includes 2> /dev/null` AC_SUBST(PYTHON3_CFLAGS) AC_SUBST(PYTHON3_LIBS) AC_SUBST(PYTHON3_INCLUDES) fi fi AM_CONDITIONAL(USE_PYTHON3, test ${use_python3} = "yes") if test "x$use_python3" = "xyes" ; then AC_CHECK_PROG([SWIG],[swig],[swig], [no]) AS_IF([test x"$SWIG" == x"no"], [AC_MSG_ERROR([Please install swig before configuring (required by python/python3).])]) fi withval="" AC_MSG_CHECKING(whether to create Go language bindings) AC_ARG_WITH(golang, AS_HELP_STRING([--with-golang],[enable building golang bindings]), use_golang=$withval, use_golang=auto) if test "x$use_golang" = xno ; then golang_found="no" AC_MSG_RESULT(no) else AC_MSG_RESULT(testing) AC_CHECK_PROG([GOLANG],[go],[go],[no]) AS_IF([test "x$GOLANG" != "xno"],[ AC_MSG_NOTICE(Go bindings will be built) golang_found="yes" # Substitute some golang environment. GOROOT=`$GOLANG env GOROOT` AC_SUBST([GOROOT]) ], [ if test "x$use_golang" = xyes ; then AC_MSG_ERROR([Go language explicitly requested and program not found]) else AC_MSG_WARN(Go not found - go bindings will not be made) fi ]) fi AM_CONDITIONAL(HAVE_GOLANG, test "x${golang_found}" = "xyes") #auditd listener AC_MSG_CHECKING(whether to include auditd network listener support) AC_ARG_ENABLE(listener, [AS_HELP_STRING([--disable-listener], [Disable auditd network listener support])], enable_listener=$enableval, enable_listener=yes) if test "x$enable_listener" != "xno"; then AC_DEFINE(USE_LISTENER, 1, [Define if you want to use the auditd network listener.]) fi AM_CONDITIONAL(ENABLE_LISTENER, test "x$enable_listener" != "xno") AC_MSG_RESULT($enable_listener) #audisp zos-remote plugin AC_ARG_ENABLE(zos-remote, [AS_HELP_STRING([--disable-zos-remote], [Disable audisp ZOS remote plugin])], enable_zos_remote=$enableval, enable_zos_remote=yes) if test $enable_zos_remote = yes; then AC_CHECK_HEADER(lber.h, ldap_headers=yes, ldap_headers=no) AC_CHECK_LIB(lber, ber_free, LDAP_LDADD=-llber) if test x$LDAP_LDADD = x ; then AC_MSG_ERROR(zos remote support was requested but the openldap library was not found) fi if test $ldap_headers = no ; then AC_MSG_ERROR(openldap libraries found but headers are missing) fi fi AC_MSG_CHECKING(whether to include audisp ZOS remote plugin) AM_CONDITIONAL(ENABLE_ZOS_REMOTE, test "x$enable_zos_remote" != "xno") AC_MSG_RESULT($enable_zos_remote) #gssapi AC_ARG_ENABLE(gssapi_krb5, [AS_HELP_STRING([--enable-gssapi-krb5],[Enable GSSAPI Kerberos 5 support @<:@default=no@:>@])], [case "${enableval}" in yes) want_gssapi_krb5="yes" ;; no) want_gssapi_krb5="no" ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-gssapi-krb5) ;; esac], [want_gssapi_krb5="no"] ) if test $want_gssapi_krb5 = yes; then AC_CHECK_LIB(gssapi_krb5, gss_acquire_cred, [ AC_CHECK_HEADER(gssapi/gssapi.h, [ AC_DEFINE(USE_GSSAPI,, Define if you want to use GSSAPI) gss_libs="-lgssapi_krb5 -lkrb5" AC_SUBST(gss_libs) ]) ]) fi AM_CONDITIONAL(ENABLE_GSSAPI, test x$want_gssapi_krb5 = xyes) # ids AC_MSG_CHECKING(whether to enable experimental options) AC_ARG_ENABLE(experimental, [AS_HELP_STRING([--enable-experimental],[Enable experimental audit components @<:@default=no@:>@])], [case "${enableval}" in yes) want_exper="yes" ;; no) want_exper="no" ;; *) AC_MSG_ERROR(bad value ${enableval} for --enable-experimental) ;; esac], [want_exper="no"] ) AM_CONDITIONAL(ENABLE_EXPERIMENTAL, test x$want_exper = xyes) AC_MSG_RESULT($want_exper) # linux/fanotify.h AC_CHECK_HEADER(linux/fanotify.h, [ AC_DEFINE(USE_FANOTIFY, [], [Defined when fanotify headers are found]) ]) withval="" WFLAGS="" AC_MSG_CHECKING(for -Wformat-truncation) TMPCFLAGS="${CFLAGS}" CFLAGS="${CFLAGS} -Wformat-truncation" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[WFLAGS="-Wno-format-truncation" AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS="${TMPCFLAGS}" CFLAGS="${CFLAGS} -Wunused-but-set-variable" AC_LINK_IFELSE([AC_LANG_PROGRAM([[]], [[]])],[WFLAGS="${WFLAGS} -Wno-unused-but-set-variable" AC_MSG_RESULT(yes)], [AC_MSG_RESULT(no)]) CFLAGS="${TMPCFLAGS}" AC_SUBST(WFLAGS) withval="" AC_MSG_CHECKING(whether to include arm eabi processor support) AC_ARG_WITH(arm, AS_HELP_STRING([--with-arm],[enable Arm eabi processor support]), use_arm=$withval, use_arm=no) if test x$use_arm != xno ; then AC_DEFINE(WITH_ARM,1,[Define if you want to enable Arm eabi processor support.]) fi AM_CONDITIONAL(USE_ARM, test x$use_arm = xyes) AC_MSG_RESULT($use_arm) withval="" AC_MSG_CHECKING(whether to include aarch64 processor support) AC_ARG_WITH(aarch64, AS_HELP_STRING([--with-aarch64],[enable Aarch64 processor support]), use_aarch64=$withval, use_aarch64=no) if test x$use_aarch64 != xno ; then AC_DEFINE(WITH_AARCH64,1,[Define if you want to enable Aarch64 processor support.]) fi AM_CONDITIONAL(USE_AARCH64, test x$use_aarch64 = xyes) AC_MSG_RESULT($use_aarch64) withval="" AC_MSG_CHECKING(whether to include riscv processor support) AC_ARG_WITH(riscv, AS_HELP_STRING([--with-riscv],[enable riscv processor support]), use_riscv=$withval, use_riscv=no) if test x$use_riscv != xno ; then AC_DEFINE(WITH_RISCV,1,[Define if you want to enable RISC-V processor support.]) fi AM_CONDITIONAL(USE_RISCV, test x$use_riscv = xyes) AC_MSG_RESULT($use_riscv) withval="" AC_MSG_CHECKING(whether to use apparmor) AC_ARG_WITH(apparmor, AS_HELP_STRING([--with-apparmor],[enable AppArmor events]), use_apparmor=$withval, use_apparmor=no) if test x$use_apparmor != xno ; then AC_DEFINE(WITH_APPARMOR,1,[Define if you want to enable AppArmor events.]) fi AC_MSG_RESULT($use_apparmor) withval="" AC_MSG_CHECKING(whether to use libwrap) AC_ARG_WITH(libwrap, [ --with-libwrap[=PATH] Compile in libwrap (tcp_wrappers) support.], [ case "$withval" in no) AC_MSG_RESULT(no) ;; yes) AC_MSG_RESULT(yes) AC_CHECK_HEADER(tcpd.h, [], AC_MSG_ERROR([Could not find libwrap headers]),) AC_CHECK_LIB(wrap, request_init, [ LIBWRAP_LIBS="-lwrap" ]) AC_CHECK_LIB(nsl, yp_get_default_domain, [ LIBWRAP_LIBS="$LIBWRAP_LIBS -lnsl" ]) ;; *) AC_MSG_RESULT(yes) if test -d "$withval"; then LIBWRAP_LIBS="-L$withval -lwrap" else LIBWRAP_LIBS="$withval" fi AC_CHECK_HEADER(tcpd.h, [], AC_MSG_ERROR([Could not find libwrap headers])) AC_CHECK_LIB(wrap, request_init, []) AC_CHECK_LIB(nsl, yp_get_default_domain, [ LIBWRAP_LIBS="$LIBWRAP_LIBS -lnsl" ]) OLDLIBS="$LIBS" LIBS="$LIBWRAP_LIBS $LIBS" AC_LINK_IFELSE([AC_LANG_PROGRAM( [[ int allow_severity; int deny_severity; ]], [[ hosts_access(); ]])],[], [ AC_MSG_ERROR(Could not find the $withval library. You must first install tcp_wrappers.) ]) LIBS="$OLDLIBS" ;; esac ], AC_MSG_RESULT(no) ) if test x"$LIBWRAP_LIBS" != "x"; then AC_DEFINE_UNQUOTED(HAVE_LIBWRAP, [], Define if tcp_wrappers support is enabled ) fi withval="" AC_MSG_CHECKING(whether to include io_uring support) AC_ARG_WITH(io_uring, AS_HELP_STRING([--with-io_uring],[enable io_uring support]), use_io_uring=$withval, use_io_uring=no) if test x$use_io_uring != xno ; then AC_DEFINE(WITH_IO_URING,1,[Define if you want to enable io_uring support.]) fi AC_MSG_RESULT($use_io_uring) # linux/ipx.h - deprecated in 2018 AC_CHECK_HEADER(linux/ipx.h, ipx_headers=yes, ipx_headers=no) if test $ipx_headers = yes ; then AC_DEFINE(HAVE_IPX_HEADERS,1,[IPX packet interpretation]) fi # Determine firewall control utility AC_ARG_WITH([nftables], AS_HELP_STRING([--with-nftables], [use nftables (default is nftables)]), with_nftables=$withval, with_nftables=yes) AC_MSG_CHECKING([which firewall command to use]) if test "x$with_nftables" = xyes ; then AC_DEFINE([USE_NFTABLES], [1], [Define if nftables should be used to manage firewall rules]) fwchoice="nftables" else AC_DEFINE([USE_IPTABLES], [1], [Define if iptables should be used to manage firewall rules]) fwchoice="iptables" fi AC_MSG_RESULT([$fwchoice]) # See if we want to support lower capabilities for plugins LIBCAP_NG_PATH AC_SUBST(DEBUG) AC_SUBST(LIBWRAP_LIBS) #AC_SUBST(libev_LIBS) AC_CONFIG_FILES(Makefile common/Makefile lib/Makefile lib/audit.pc lib/test/Makefile auparse/Makefile auparse/test/Makefile auparse/auparse.pc src/Makefile src/libev/Makefile src/test/Makefile docs/Makefile rules/Makefile init.d/Makefile audisp/Makefile audisp/plugins/Makefile audisp/plugins/af_unix/Makefile audisp/plugins/remote/Makefile audisp/plugins/zos-remote/Makefile audisp/plugins/syslog/Makefile audisp/plugins/filter/Makefile audisp/plugins/ids/Makefile audisp/plugins/ids/rules/Makefile audisp/plugins/statsd/Makefile bindings/Makefile bindings/python/Makefile bindings/python/python3/Makefile bindings/golang/Makefile bindings/swig/Makefile bindings/swig/src/Makefile bindings/swig/python3/Makefile tools/Makefile tools/aulast/Makefile tools/aulastlog/Makefile tools/ausyscall/Makefile m4/Makefile) AC_OUTPUT echo . echo " Auditd Version: $VERSION Target: $target Installation prefix: $prefix Compiler: $CC Compiler flags: `echo $CFLAGS | fmt -w 50 | sed 's,^, ,'` __attr_access support: $ACCESS __attr_dealloc_free support: $DEALLOC " audit-userspace-4.0.5/contrib/000077500000000000000000000000001501761310600162565ustar00rootroot00000000000000audit-userspace-4.0.5/contrib/avc_snap000077500000000000000000000051511501761310600200000ustar00rootroot00000000000000#! /usr/bin/env python import os, string, select, struct, syslog import audit, avc, traceback import AuditMsg from setroubleshoot.signature import * from setroubleshoot.util import LoadPlugins class avc_snap: def __init__(self): self.audit_list = [] self.cur_sig = "" self.plugins = LoadPlugins() syslog.syslog( "Number of Plugins = %d" % len(self.plugins)) def is_avc(self): for i in self.audit_list: if i[0] == audit.AUDIT_AVC: return True return False def out(self): if self.is_avc(): rules=avc.SERules() l=[] for ( type, data_list ) in self.audit_list: l += data_list if "granted" in l: self.audit_list = [] return rules.translate(l) myavc = AVC(rules.AVCS[0]) for plugin in self.plugins: try: if plugin.analyze(myavc): plugin.report() break; except TypeError, e: syslog.syslog("Type exception %s: %s " % ( plugin.analysisID, e.args)) except: syslog.syslog("Plugin Exception %s " % plugin.analysisID) self.audit_list = [] def process(self, type, data): data_list=data.split() new_sig=data_list[0] if len(self.audit_list) > 0 and new_sig != self.cur_sig: self.out() self.cur_sig = new_sig self.audit_list.append((type, data_list[1:])) def run(self): while 1: input,output, err = select.select([0],[], [], 5) try: if 0 in input: msg = AuditMsg.AuditMsg() if not msg.read_from_fd(0): syslog.syslog("Connection closing") return self.process(msg.get_type(), msg.get_body()) else: self.out() except struct.error, e: syslog.syslog("struct exception %s " % e.args) return except TypeError, e: syslog.syslog("Type exception %s " % e.args) try: syslog.openlog("avc_snap") snap=avc_snap() snap.run() except IOError,e: syslog.syslog("IOError exception %s" % e.args) except Exception, e: syslog.syslog("Unexpected exception %s " % e.args) syslog.syslog(traceback.format_exc()) except: syslog.syslog("Caught Exception") syslog.syslog(traceback.format_exc()) audit-userspace-4.0.5/contrib/plugin/000077500000000000000000000000001501761310600175545ustar00rootroot00000000000000audit-userspace-4.0.5/contrib/plugin/Makefile000066400000000000000000000002241501761310600212120ustar00rootroot00000000000000CFLAGS=-g -W -Wall -Wundef LIBS= -lauparse -laudit all: gcc $(CFLAGS) audisp-example.c -o audisp-example $(LIBS) clean: rm -f audisp-example *.o audit-userspace-4.0.5/contrib/plugin/audisp-example.c000066400000000000000000000161531501761310600226440ustar00rootroot00000000000000/* audisp-example.c -- * Copyright 2012 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * * This is a sample program to demonstrate several concepts of how to * write an audispd plugin using libauparse. It can be tested by using a * file of raw audit records. You can generate the test file like: * * ausearch --start today --raw > test.log. * * Then you can test this app by: cat test.log | ./audisp-example * * It will print things to stdout. In a real program, you wouldn't * do anything with stdout since that is likely to be pointing to /dev/null. * * Excluding some init/destroy items you might need to add to main, the * event_handler function is the main place that you would modify to do * things specific to your plugin. * * Also, note that for a "real" plugin, you may have to add an internal queue * to your application. If plugins do any kind of networking or in depth * processing of incoming events, auditd's internal queue can overflow because * the socket connecting to the plugin's stdin get backed up. When audit has * nowhere to put events, the kernel's audit backlog can get filled up. * If that happens, the backlog_wait_time is consulted by the kernel which * may have the effect of slowing down the whole system. A good design would be * to have 2 threads, one watching for inbound events and one doing the * processing of the events with a configurable queue in between. */ #define _GNU_SOURCE #include #include #include #include #include #include #include "libaudit.h" #include "auparse.h" /* Global Data */ static volatile int stop = 0; static volatile int hup = 0; static auparse_state_t *au = NULL; /* Local declarations */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); /* * SIGTERM handler */ static void term_handler(int sig) { stop = 1; } /* * SIGHUP handler: re-read config */ static void hup_handler(int sig) { hup = 1; } static void reload_config(void) { hup = 0; /* * Add your code here that re-reads the config file and changes * how your plugin works. */ } int main(int argc, char *argv[]) { char tmp[MAX_AUDIT_MESSAGE_LENGTH]; struct sigaction sa; /* Register sighandlers */ sa.sa_flags = 0; sigemptyset(&sa.sa_mask); /* Set handler for the ones we care about */ sa.sa_handler = term_handler; sigaction(SIGTERM, &sa, NULL); sa.sa_handler = hup_handler; sigaction(SIGHUP, &sa, NULL); /* Set STDIN non-blocking */ fcntl(0, F_SETFL, O_NONBLOCK); /* Initialize the auparse library */ au = auparse_init(AUSOURCE_FEED, 0); if (au == NULL) { printf("audisp-example is exiting due to auparse init errors"); return -1; } auparse_set_eoe_timeout(2); auparse_add_callback(au, handle_event, NULL, NULL); do { fd_set read_mask; int retval; int read_size = 1; /* Set to 1 so it's not EOF */ /* Load configuration */ if (hup) { reload_config(); } do { FD_ZERO(&read_mask); FD_SET(0, &read_mask); if (auparse_feed_has_data(au)) { struct timeval tv; tv.tv_sec = 1; tv.tv_usec = 0; retval= select(1, &read_mask, NULL, NULL, &tv); } else retval= select(1, &read_mask, NULL, NULL, NULL); /* If we timed out & have events, shake them loose */ if (retval == 0 && auparse_feed_has_data(au)) auparse_feed_age_events(au); } while (retval == -1 && errno == EINTR && !hup && !stop); /* Now the event loop */ if (!stop && !hup && retval > 0) { while ((read_size = read(0, tmp, MAX_AUDIT_MESSAGE_LENGTH)) > 0) { auparse_feed(au, tmp, read_size); } } if (read_size == 0) /* EOF */ break; } while (stop == 0); /* Flush any accumulated events from queue */ auparse_flush_feed(au); auparse_destroy(au); if (stop) printf("audisp-example is exiting on stop request\n"); else printf("audisp-example is exiting on stdin EOF\n"); return 0; } /* This function shows how to dump a whole event by iterating over records */ static void dump_whole_event(auparse_state_t *au) { auparse_first_record(au); do { printf("%s\n", auparse_get_record_text(au)); } while (auparse_next_record(au) > 0); printf("\n"); } /* This function shows how to dump a whole record's text */ static void dump_whole_record(auparse_state_t *au) { printf("%s: %s\n", audit_msg_type_to_name(auparse_get_type(au)), auparse_get_record_text(au)); printf("\n"); } /* This function shows how to iterate through the fields of a record * and print its name and raw value and interpreted value. */ static void dump_fields_of_record(auparse_state_t *au) { printf("record type %d(%s) has %d fields\n", auparse_get_type(au), audit_msg_type_to_name(auparse_get_type(au)), auparse_get_num_fields(au)); printf("line=%d file=%s\n", auparse_get_line_number(au), auparse_get_filename(au) ? auparse_get_filename(au) : "stdin"); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) { printf("Error getting timestamp - aborting\n"); return; } /* Note that e->sec can be treated as time_t data if you want * something a little more readable */ printf("event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec, e->milli, e->serial, e->host ? e->host : "?"); auparse_first_field(au); do { printf("field: %s=%s (%s)\n", auparse_get_field_name(au), auparse_get_field_str(au), auparse_interpret_field(au)); } while (auparse_next_field(au) > 0); printf("\n"); } /* This function receives a single complete event at a time from the auparse * library. This is where the main analysis code would be added. */ static void handle_event(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { int type, num=0; if (cb_event_type != AUPARSE_CB_EVENT_READY) return; /* Loop through the records in the event looking for one to process. We use physical record number because we may search around and move the cursor accidentally skipping a record. */ while (auparse_goto_record_num(au, num) > 0) { type = auparse_get_type(au); /* Now we can branch based on what record type we find. This is just a few suggestions, but it could be anything. */ switch (type) { case AUDIT_AVC: dump_fields_of_record(au); break; case AUDIT_SYSCALL: dump_whole_record(au); break; case AUDIT_USER_LOGIN: break; case AUDIT_ANOM_ABEND: break; case AUDIT_MAC_STATUS: dump_whole_event(au); break; default: break; } num++; } } audit-userspace-4.0.5/contrib/plugin/audisp-example.conf000066400000000000000000000003341501761310600233410ustar00rootroot00000000000000# This file controls the configuration of the # example syslog plugin. It simply takes events and writes # them to syslog. active = no direction = out path = /sbin/audisp-example type = always args = 1 format = string audit-userspace-4.0.5/docs/000077500000000000000000000000001501761310600155465ustar00rootroot00000000000000audit-userspace-4.0.5/docs/Makefile.am000066400000000000000000000065101501761310600176040ustar00rootroot00000000000000# Makefile.am -- # Copyright 2004-09,2012,2014-18 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig EXTRA_DIST = $(man_MANS) man_MANS = audit_add_rule_data.3 audit_add_watch.3 auditctl.8 auditd.8 \ auditd.conf.5 auditd-plugins.5 \ audit_delete_rule_data.3 audit_detect_machine.3 \ audit_encode_nv_string.3 audit_getloginuid.3 \ audit_get_reply.3 audit_get_session.3 \ audit_log_acct_message.3 audit_log_user_avc_message.3 \ audit_log_user_command.3 audit_log_user_comm_message.3 \ audit_log_user_message.3 audit_log_semanage_message.3 \ auparse_new_buffer.3 audit_open.3 audit_close.3 \ audit_is_enabled.3 audit_request_rules_list_data.3 \ audit_request_signal_info.3 audit_request_status.3 audit.rules.7 \ audit_set_backlog_limit.3 audit_set_enabled.3 audit_set_failure.3 \ audit_setloginuid.3 audit_set_pid.3 audit_set_rate_limit.3 \ audit_update_watch_perms.3 audit_value_needs_encoding.3 \ audit_encode_value.3 auparse_add_callback.3 audit_name_to_syscall.3 \ audit_syscall_to_name.3 audit_name_to_errno.3\ audit_fstype_to_name.3 audit_name_to_fstype.3 \ audit_name_to_action.3 \ audit_flag_to_name.3 audit_name_to_flag.3 \ audit_fgets.3 \ auparse_destroy.3 auparse_feed.3 auparse_feed_age_events.3 \ auparse_feed_has_data.3 auparse_find_field.3 \ auparse_find_field_next.3 auparse_first_field.3 auparse_first_record.3 \ auparse_flush_feed.3 auparse_get_field_int.3 auparse_get_field_name.3 \ auparse_get_field_str.3 auparse_get_field_type.3 auparse_get_filename.3 \ auparse_get_line_number.3 auparse_get_milli.3 \ auparse_get_node.3 auparse_get_num_fields.3 \ auparse_get_num_records.3 auparse_get_record_text.3 \ auparse_get_serial.3 auparse_get_time.3 auparse_get_timestamp.3 \ auparse_get_type.3 auparse_get_type_name.3 \ auparse_get_field_num.3 auparse_get_record_num.3 \ auparse_goto_field_num.3 auparse_goto_record_num.3 \ auparse_init.3 auparse_interpret_field.3 auparse_metrics.3 \ auparse_next_event.3 auparse_next_field.3 auparse_next_record.3 \ auparse_node_compare.3 auparse_reset.3 auparse_set_escape_mode.3 \ auparse_normalize.3 auparse_normalize_functions.3 \ auparse_timestamp_compare.3 auparse_set_eoe_timeout.3 ausearch-expression.5 \ aureport.8 ausearch.8 ausearch_add_item.3 ausearch_add_interpreted_item.3 \ ausearch_add_expression.3 ausearch_add_timestamp_item.3 ausearch_add_regex.3 \ ausearch_add_timestamp_item_ex.3 ausearch_clear.3 \ ausearch_next_event.3 ausearch_cur_event.3 ausearch_set_stop.3 \ get_auditfail_action.3 set_aumessage_mode.3 \ audispd-zos-remote.8 libaudit.conf.5 \ augenrules.8 audit_set_backlog_wait_time.3 \ zos-remote.conf.5 \ auditd.cron.5 audit-userspace-4.0.5/docs/audispd-zos-remote.8000066400000000000000000000224231501761310600213750ustar00rootroot00000000000000.\" Copyright (c) International Business Machines Corp., 2007 .\" .\" This program is free software; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2 of .\" the License, or (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See .\" the GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, .\" MA 02111-1307 USA .\" .\" Changelog: .\" 2007-10-06, created by Klaus Heinrich Kiwi .\" .TH AUDISPD-ZOS-REMOTE 8 "Oct 2007" "IBM" "System Administration Utilities" .SH NAME audispd\-zos\-remote \- z/OS Remote-services Audit dispatcher plugin .SH SYNOPSIS .B audispd\-zos\-remote [ .I config-file .B ] .SH DESCRIPTION .B audispd\-zos\-remote is a remote-auditing plugin for the Audit subsystem. It should be started by the .BR auditd (8) daemon and will forward all incoming audit events, as they happen, to a configured z/OS SMF (Service Management Facility) database, through an IBM Tivoli Directory Server (ITDS) set for Remote Audit service. See .B SMF MAPPING section below for more information about the resulting SMF record format. .BR auditd (8) must be configured to start the plugin. This is done by a configuration file usually located at .IR /etc/audit/plugins.d/audispd\-zos\-remote.conf , but multiple instances can be spawned by having multiple configuration files in .I /etc/audit/plugins.d for the same plugin executable (see .BR auditd (8)). Each instance needs a configuration file, located by default at .IR /etc/audit/zos\-remote.conf . Check .BR zos\-remote.conf (5) for details about the plugin configuration. .SH OPTIONS .IP config-file Use an alternate configuration file instead of .IR /etc/audit/zos\-remote.conf . .SH SIGNALS .B audispd\-zos\-remote reacts to SIGTERM and SIGHUP signals (according to the .BR auditd (8) specification): .TP .B SIGHUP Instructs the .B audispd\-zos\-remote plugin to re-read it's configuration and flush existing network connections. .TP .B SIGTERM Performs a clean exit. .B audispd\-zos\-remote will wait up to 10 seconds if there are queued events to be delivered, dropping any remaining queued events after that time. .SH IBM z/OS ITDS Server and RACF configuration In order to use this plugin, you must have an IBM z/OS v1R8 (or higher) server with IBM Tivoli Directory Server (ITDS) configured for Remote Audit service. For more detailed information about how to configure the z/OS server for Remote Auditing, refer to .B z/OS V1R8.0-9.0 Integrated Security Services Enterprise Identity Mapping (EIM) Guide and Reference .nf .RI ( http://publibz.boulder.ibm.com/cgi\-bin/bookmgr_OS390/FRAMESET/EIMA1140/CCONTENTS?DT=20070827115119 ), chapter "2.0 - Working with remote services". .fi .SS Enable ITDS to process Remote Audit requests To enable ITSD to process Remote Audit requests, the user ID associated with ITDS must be granted READ access to the IRR.AUDITX FACILITY Class profile (the profile used to protect the R_Auditx service). This user ID can usually be found in the STARTED Class profile for the ITDS started procedure. If the identity associated with ITDS is .IR ITDSUSER , the administrator can configure RACF to grant Remote Auditing processing to ITDS with the following TSO commands: .TP .I TSO Commands: Grant ITDSUSER READ access to IRR.AUDITX FACILITY Class profile .nf rdefine FACILITY IRR.RAUDITX uacc(none) permit IRR.RAUDITX class(FACILITY) id(ITDSUSER) access(READ) .fi .SS Create/enable RACF user ID to perform Remote Audit requests A z/OS RACF user ID is needed by the plugin - Every Audit request performed by the plugin will use a RACF user ID, as configured in the plugin configuration .BR zos\-remote.conf (5). This user ID needs READ access to FACILITY Class resource IRR.LDAP.REMOTE.AUDIT. If the user ID is .IR BINDUSER , the administrator can configure RACF to enable this user to perform Remote Auditing requests with the following TSO commands: .TP .I TSO Commands: Enable BINDUSER to perform Remote Audit requests .nf rdefine FACILITY IRR.LDAP.REMOTE.AUDIT uacc(none) permit IRR.LDAP.REMOTE.AUDIT class(FACILITY) id(BINDUSER) access(READ) .fi .SS Add @LINUX Class to RACF When performing remote auditing requests, the .B audispd\-zos\-remote plugin will use the special .B @LINUX .I CDT Class and the audit record type (eg.: .BR SYSCALL , .BR AVC , .BR PATH ...) as the .I CDT Resource Class for all events processed. To make sure events are logged, the RACF server must be configured with a Dynamic CDT Class named .B @LINUX with correct sizes and attributes. The following TSO commands can be used to add this class: .TP .I TSO Commands: Add @LINUX CDT Class .nf rdefine cdt @LINUX cdtinfo(posit(493) FIRST(alpha,national,numeric,special) OTHER(alpha,national,numeric,special) RACLIST(REQUIRED) case(asis) generic(allowed) defaultuacc(none) maxlength(246)) setr classact(cdt) setr raclist(cdt) setr raclist(cdt) refresh setr classact(@LINUX) setr raclist(@LINUX) setr generic(@LINUX) .fi .SS Add profiles to the @LINUX Class Once the CDT Class has been defined, you can add profiles to it, specifying resources (wildcards allowed) to log or ignore. The following are examples: .TP .I TSO Commands: Log only AVC records (One generic and one discrete profile): .nf rdefine @LINUX * uacc(none) audit(none(read)) rdefine @LINUX AVC uacc(none) audit(all(read)) setr raclist(@LINUX) refresh .fi .TP .I TSO Commands: Log everything (One generic profile): .nf rdefine @LINUX * uacc(none) audit(all(read)) setr raclist(@LINUX) refresh .fi .P Resources always match the single profile with the .I best match. There are many other ways to define logging in RACF. Please refer to the server documentation for more details. .SH SMF Mapping The ITDS Remote Audit service will cut SMF records of type 83 subtype 4 every time it processes a request. This plugin will issue a remote audit request for every incoming Linux Audit record (meaning that one Linux record will map to one SMF record), and fill this type's records with the following: .SS Link Value The Linux event serial number, encoded in network-byte order hexadecimal representation. Records within the same Event share the same Link Value. .SS Violation Always zero (0) - .I False .SS Event Code Always two (2) - .I Authorization event .SS Event Qualifier Zero (0) - .IR Success , if the event reported .B success=yes or .BR res=success , Three (3) - .IR Fail , if the event reported .B success=no or .BR res=failed , or One (1) - .I Info otherwise. .SS Class Always .I @LINUX .SS Resource The Linux record type for the processed record. e.g.: .IR SYSCALL , AVC , PATH , CWD etc. .SS Log String Textual message bringing the RACF user ID used to perform the request, plus the Linux hostname and the record type for the first record in the processed event. e.g.: .I Remote audit request from RACFUSER. Linux (hostname.localdomain):USER_AUTH .SS Data Field List Also known as .IR relocates , this list will bring all the field names and values in a .B fieldname=value format, as a type 114 .RB ( "Application specific Data" ) relocate. The plug-in will try to interpret those fields (i.e.: use human-readable username .B root instead of numeric userid .BR 0 ) whenever possible. Currently, this plugin will also add a relocate type 113 .RB ( "Date And Time Security Event Occurred" ) with the Event Timestamp in the format as returned by .BR ctime (3). .SH ERRORS Errors and warnings are reported to syslog (under DAEMON facility). In situations where the event was submitted but the z/OS server returned an error condition, the logged message brings a name followed by a human-readable description. Below are some common errors conditions: .TP .B NOTREQ - No logging required Resource (audit record type) is not set to be logged in the RACF server - The @LINUX Class profile governing this audit record type is set to ignore. See .B IBM z/OS RACF Server configuration .TP .B UNDETERMINED - Undetermined result No profile found for specified resource. There is no @LINUX Class configured or no @LINUX Class profile associated with this audit record type. See .B IBM z/OS RACF Server configuration .TP .B UNAUTHORIZED - The user does not have authority the R_auditx service The user ID associated with the ITDS doesn't have READ access to the IRR.AUDITX FACILITY Class profile. See .B IBM z/OS RACF Server configuration .TP .B UNSUF_AUTH - The user has insufficient authority for the requested function The RACF user ID used to perform Remote Audit requests (as configured in .BR zos-remote.conf (5)) don't have access to the IRR.LDAP.REMOTE.AUDIT FACILITY Class profile. See .B IBM z/OS RACF Server configuration .SH BUGS The plugin currently does remote auditing in a best-effort basis, and will discard events in case the z/OS server cannot be contacted (network failures) or in any other case that event submission fails. .SH FILES /etc/audit/plugins.d/audispd\-zos\-remote.conf /etc/audit/zos\-remote.conf .SH "SEE ALSO" .BR auditd (8), .BR zos\-remote.conf (5). .SH AUTHOR Klaus Heinrich Kiwi audit-userspace-4.0.5/docs/audit.rules.7000066400000000000000000000312561501761310600201040ustar00rootroot00000000000000.TH AUDIT.RULES "7" "Sep 2023" "Red Hat" "System Administration Utilities" .SH NAME audit.rules \- a set of rules loaded in the kernel audit system .SH DESCRIPTION \fBaudit.rules\fP is a file containing audit rules that will be loaded by the audit daemon's init script whenever the daemon is started. The auditctl program is used by the initscripts to perform this operation. The syntax for the rules is essentially the same as when typing in an auditctl command at a shell prompt except you do not need to type the auditctl command name since that is implied. The audit rules come in 3 varieties: .IR control ", " file ", and " syscall ". .SS Control Control commands generally involve configuring the audit system rather than telling it what to watch for. These commands typically include deleting all rules, setting the size of the kernel's backlog queue, setting the failure mode, setting the event rate limit, or to tell auditctl to ignore syntax errors in the rules and continue loading. Generally, these rules are at the top of the rules file. .SS File System File System rules are sometimes called watches. These rules are used to audit access to particular files or directories that you may be interested in. If the path given in a watch rule is a directory, then the rule used is recursive to the bottom of the directory tree excluding any directories that may be mount points. The syntax of these watch rules generally follow this format: .nf .B \-a always,exit \-F arch=b64 -F path=path-to-file -F perm=permissions -F key=keyname .fi where the permission are any one of the following: .RS .TP 2 .B r - read of the file .TP .B w - write to the file .TP .B x - execute the file .TP .B a - change in the file's attribute .RE For best performance, you should supply an .B arch field in the rule. The individual permissions will cause the selection of specific system calls that use that kind of access. Not supplying the arch will cause the selection of all system calls which will affect performance as all system calls will be evaluated. Watches can also be created using the deprecated \-w format which allows for backwards compatibility at the expense of system performance as explained. Using syscall rules as shown above, you can choose between .B path and .B dir which is against a specific inode or directory tree respectively. It should also be noted that the recursive directory watch will stop if there is a mount point below the parent directory. There is an option to make the mounted subdirectory equivalent by using a .B -q rule. .SS System Call The system call rules are loaded into a matching engine that intercepts each syscall that all programs on the system makes. Therefore it is very important to only use syscall rules when you have to since these affect performance. The more rules, the bigger the performance hit. You can help the performance, though, by combining syscalls into one rule whenever possible. The Linux kernel has 6 rule matching lists or filters as they are sometimes called. They are: task, exit, user, exclude, filesystem, and io_uring. The task list is checked only during the fork or clone syscalls. It is rarely used in practice. The exit filter is the place where all syscall and file system audit requests are evaluated. The user filter is used to filter (remove) some events that originate in user space. By default, any event originating in user space is allowed. So, if there are some events that you do not want to see, then this is a place where some can be removed. See auditctl(8) for fields that are valid. The exclude filter is used to exclude certain events from being emitted. The msgtype and a number of subject attribute fields can be used to tell the kernel which message types you do not want to record. This filter can remove the event as a whole and is not selective about any other attribute. The user and exit filters are better suited to selectively auditing events. The action is ignored for this filter, defaulting to "never". The io_uring filter is used to watch underlying syscalls performed by io_uring operations. Syscall rules take the general form of: .nf .B \-a action,list \-S syscall \-F field=value \-k keyname .fi The .B \-a option tells the kernel's rule matching engine that we want to append a rule at the end of the rule list. But we need to specify which rule list it goes on and what action to take when it triggers. Valid actions are: .RS .TP 7 .B always - always create an event .TP .B never - never create an event .RE The action and list are separated by a comma but no space in between. Valid lists are: .IR task ", " exit ", " user ", " exclude ", " filesystem ", and "io_uring ". Their meaning was explained earlier. Next in the rule would normally be the .B \-S option. This field can either be the syscall name or number. For readability, the name is almost always used. You may give more than one syscall in a rule by specifying another .B \-S option. When sent into the kernel, all syscall fields are put into a mask so that one compare can determine if the syscall is of interest. So, adding multiple syscalls in one rule is very efficient. When you specify a syscall name, auditctl will look up the name and get its syscall number. This leads to some problems on bi-arch machines. The 32 and 64 bit syscall numbers sometimes, but not always, line up. So, to solve this problem, you would generally need to break the rule into 2 with one specifying \-F arch=b32 and the other specifying \-F arch=b64. This needs to go in front of the .B \-S option so that auditctl looks at the right lookup table when returning the number. After the syscall is specified, you would normally have one or more .B \-F options that fine tune what to match against. Rather than list all the valid field types here, the reader should look at the auditctl man page which has a full listing of each field and what it means. But it's worth mentioning a couple things. The audit system considers uids to be unsigned numbers. The audit system uses the number \-1 to indicate that a loginuid is not set. This means that when it's printed out, it looks like 4294967295. But when you write rules, you can use either "unset" which is easy to remember, or -1, or 4294967295. They are all equivalent. If you write a rule that you wanted try to get the valid users of the system, you need to look in /etc/login.defs to see where user accounts start. For example, if UID_MIN is 1000, then you would also need to take into account that the unsigned representation of \-1 is higher than 500. So you would address this with the following piece of a rule: .nf \-F auid>=1000 \-F auid!=unset .fi These individual checks are "anded" and both have to be true. The last thing to know about syscall rules is that you can add a key field which is a free form text string that you want inserted into the event to help identify its meaning. This is discussed in more detail in the NOTES section. .SH NOTES The purpose of auditing is to be able to do an investigation periodically or whenever an incident occurs. A few simple steps in planning up front will make this job easier. The best advice is to use keys in both the watches and system call rules to give the rule a meaning. If rules are related or together meet a specific requirement, then give them a common key name. You can use this during your investigation to select only results with a specific meaning. When doing an investigation, you would normally start off with the main aureport output to just get an idea about what is happening on the system. This report mostly tells you about events that are hard coded by the audit system such as login/out, uses of authentication, system anomalies, how many users have been on the machine, and if SE Linux has detected any AVCs. .nf aureport \-\-start this-week .fi After looking at the report, you probably want to get a second view about what rules you loaded that have been triggering. This is where keys become important. You would generally run the key summary report like this: .nf aureport \-\-start this-week \-\-key \-\-summary .fi This will give an ordered listing of the keys associated with rules that have been triggering. If, for example, you had a syscall audit rule that triggered on the failure to open files with EPERM that had a key field of access like this: .nf \-a always,exit \-F arch=b64 \-S open \-S openat \-S openat2 \-F exit=\-EPERM \-k access .fi Then you can isolate these failures with ausearch and pipe the results to aureport for display. Suppose your investigation noticed a lot of the access denied events. If you wanted to see the files that unauthorized access has been attempted, you could run the following command: .nf ausearch \-\-start this-week \-k access \-\-raw | aureport \-\-file \-\-summary .fi This will give an ordered list showing which files are being accessed with the EPERM failure. Suppose you wanted to see which users might be having failed access, you would run the following command: .nf ausearch \-\-start this-week \-k access \-\-raw | aureport \-\-user \-\-summary .fi If your investigation showed a lot of failed accesses to a particular file, you could run the following report to see who is doing it: .fi ausearch \-\-start this-week \-k access \-f /path-to/file \-\-raw | aureport \-\-user \-i .fi This report will give you the individual access attempts by person. If you needed to see the actual audit event that is being reported, you would look at the date, time, and event columns. Assuming the event was 822 and it occurred at 2:30 on 09/01/2009 and you use the en_US.utf8 locale, the command would look something like this: .nf ausearch \-\-start 09/01/2009 02:30 \-a 822 \-i \-\-just\-one .fi This will select the first event from that day and time with the matching event id and interpret the numeric values into human readable values. The most important step in being able to do this kind of analysis is setting up key fields when the rules were originally written. It should also be pointed out that you can have more than one key field associated with any given rule. .SH TROUBLESHOOTING If you are not getting events on syscall rules that you think you should, try running a test program under strace so that you can see the syscalls. There is a chance that you might have identified the wrong syscall. If you get a warning from auditctl saying, "32/64 bit syscall mismatch in line XX, you should specify an arch". This means that you specified a syscall rule on a bi-arch system where the syscall has a different syscall number for the 32 and 64 bit interfaces. This means that on one of those interfaces you are likely auditing the wrong syscall. To solve the problem, re-write the rule as two rules specifying the intended arch for each rule. For example, .nf \-a always,exit \-S openat \-k access .fi would be rewritten as .nf \-a always,exit \-F arch=b32 \-S openat \-k access \-a always,exit \-F arch=b64 \-S openat \-k access .fi If you get a warning that says, "entry rules deprecated, changing to exit rule". This means that you have a rule intended for the entry filter, but that filter is no longer available. Auditctl moved your rule to the exit filter so that it's not lost. But to solve this so that you do not get the warning any more, you need to change the offending rule from entry to exit. .SH EXAMPLES The following rule shows how to audit failed access to files due to permission problems. Note that it takes two rules for each arch ABI to audit this since file access can fail with two different failure codes indicating permission problems. .nf .B \-a always,exit \-F arch=b32 \-S open,openat,openat2 \-F exit=\-EACCES \-k access .B \-a always,exit \-F arch=b32 \-S open,openat,openat2 \-F exit=\-EPERM \-k access .B \-a always,exit \-F arch=b64 \-S open,openat,openat2 \-F exit=\-EACCES \-k access .B \-a always,exit \-F arch=b64 \-S open,openat,openat2 \-F exit=\-EPERM \-k access .fi .SH IO_URING RULES Io_uring rules do not take an arch field. It is implicit in the specification of the filter. The following example rule watches for file opens through the io_uring subsystem: .nf .B \-a always,io_uring \-S openat,openat2 \-F key=access .SH HARD WIRED EVENTS If auditing is enabled, then you can get any event that is not caused by syscall or file watch rules (because you don't have any rules loaded). So, that means, any event from 1100-1299, 1326, 1328, 1331 and higher can be emitted. The reason that there are a number of events that are hardwired is because they are required by regulatory compliance and are sent automatically as a convenience. (For example, logon/logoff is a mandatory event in all security guidance.) If you don't want this, you can use the exclude filter to drop events that you do not want. .nf .B \-a always,exclude -F msgtype=CRED_REFR .fi .SH "SEE ALSO" .BR auditctl (8), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_add_rule_data.3000066400000000000000000000036671501761310600216040ustar00rootroot00000000000000.TH "AUDIT_ADD_RULE_DATA" "3" "Aug 2009" "Red Hat" "Linux Audit API" .SH NAME audit_add_rule_data \- Add new audit rule .SH "SYNOPSIS" .B #include .sp int audit_add_rule_data(int fd, struct audit_rule_data *rule, int flags, int action); .SH "DESCRIPTION" audit_add_rule_data adds an audit rule previously constructed with audit_rule_fieldpair_data(3) to one of several kernel event filters. The filter is specified by the flags argument. Possible values for flags are: .TP 3 \(bu AUDIT_FILTER_USER - Apply rule to userspace generated messages. This is the user filter. Normally all user space originating events are accepted. Rules on this filter are typically written to block specific events. .TP \(bu AUDIT_FILTER_TASK - Apply rule at task creation (not syscall). This is the task filter. It's normally used to exclude an application from being audited. .TP \(bu AUDIT_FILTER_EXIT - Apply rule at syscall exit. This is the main filter that is used for syscalls and filesystem watches. Normally all syscall do not trigger events, so this is normally used to specify events that are of interest. .TP \(bu AUDIT_FILTER_EXCLUDE - Apply rule at audit_log_start. This is the exclude filter which discards any records that match. The action type is ignored for this filter, defaulting to "never". .LP .TP \(bu AUDIT_FILTER_FS - Apply rule when adding PATH auxiliary records to SYSCALL events. This is the filesystem filter. This is used to ignore PATH records that are not of interest. .LP .PP The rule's action has two possible values: .TP 3 \(bu AUDIT_NEVER - Do not build context if rule matches. .TP \(bu AUDIT_ALWAYS - Generate audit record if rule matches. .LP .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_rule_fieldpair_data (3), .BR audit_delete_rule_data (3), .BR auditctl (8). .SH AUTHOR Steve Grubb. audit-userspace-4.0.5/docs/audit_add_watch.3000066400000000000000000000012001501761310600207270ustar00rootroot00000000000000.TH "AUDIT_ADD_WATCH" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME audit_add_watch \- create a rule layout for a watch .SH "SYNOPSIS" .B #include .sp int audit_add_watch(struct audit_rule_data **rulep, const char *path); .SH "DESCRIPTION" audit_add_watch will create a watch rule in the pointer to a pointer rulep. All that you need to pass it is the full path to a file and it will initialize the audit_rule_data structure for a watch. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR audit_add_rule_data (3), .BR audit_delete_rule_data (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_close.3000066400000000000000000000007751501761310600201360ustar00rootroot00000000000000.TH "AUDIT_CLOSE" "3" "Apr 2021" "Red Hat" "Linux Audit API" .SH NAME audit_close \- Close the audit netlink socket connection .SH "SYNOPSIS" .nf .B #include .PP .BI "void audit_close(int " fd ); .fi .SH "DESCRIPTION" .BR audit_close () closes the NETLINK_AUDIT socket that communicates with the kernel part of the Linux Audit Subsystem. .I fd must have been returned by .BR audit_open (3). .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR audit_open (3), .BR netlink (7). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_delete_rule_data.3000066400000000000000000000013651501761310600223070ustar00rootroot00000000000000.TH "AUDIT_DELETE_RULE_DATA" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_delete_rule_data \- Delete audit rule .SH "SYNOPSIS" .B #include .sp int audit_delete_rule_data(int fd, struct audit_rule_data *rule, int flags, int action); .SH "DESCRIPTION" audit_delete_rule_data is used to delete rules that are currently loaded in the kernel. To delete a rule, you must set up the rules identical to the one being deleted. See audit_add_rule_data for flag and action definitions. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_add_rule_data (3), .BR auditctl (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_detect_machine.3000066400000000000000000000011461501761310600217560ustar00rootroot00000000000000.TH "AUDIT_DETECT_MACHINE" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_detect_machine \- Detects the current machine type .SH "SYNOPSIS" .B #include .sp int audit_detect_machine(void); .SH "DESCRIPTION" audit_detect_machine queries uname and converts the kernel machine string to an enum value defined in machine_t. The machine type is needed for any use of the audit_name_to_syscall function. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, the return value is the machine's type. .SH "SEE ALSO" .BR uname (3), .BR audit_name_to_syscall (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_encode_nv_string.3000066400000000000000000000031161501761310600223470ustar00rootroot00000000000000.TH "AUDIT_ENCODE_NV_STRING" "3" "Oct 2010" "Red Hat" "Linux Audit API" .SH NAME audit_encode_nv_string \- encode a name/value pair in a string .SH SYNOPSIS .B #include .sp .B char *audit_encode_nv_string(const char *name, const char *value, unsigned int vlen) .SH DESCRIPTION This function is used to encode a name/value pair. This should be used on any field being logged that potentially contains a space, a double-quote, or a control character. Any value containing those have to be specially encoded for the auparse library to correctly handle the value. The encoding method is designed to prevent log injection attacks where malicious values could cause parsing errors. To use this function, pass the name string and value strings on their respective arguments. If the value is likely to have a NUL value embedded within it, you will need to pass a value length that tells in bytes how big the value is. Otherwise, you can pass a 0 for vlen and the function will simply use strlen against the value pointer. Also be aware that the name of the field will cause auparse to do certain things when interpreting the value. If the name is uid, a user id value in decimal is expected. Make sure that well known names are used for their intended purpose or that there is no chance of name collision with something new. .SH "RETURN VALUE" Returns a freshly malloc'ed string that the caller must free or NULL on error. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_user_comm_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_encode_value.3000066400000000000000000000014151501761310600214520ustar00rootroot00000000000000.TH "AUDIT_ENCODE_VALUE" "3" "May 2021" "Red Hat" "Linux Audit API" .SH NAME audit_encode_value \- encode input string to ASCII code string .SH "SYNOPSIS" .nf .B #include .PP .BI "char *audit_encode_value(char *" final ", const char *" buf ", unsigned int " size "); .fi .SH "DESCRIPTION" .BR audit_encode_value () encodes a string given by .I buf to a ASCII code string. .I final is the hexadecimal string encoded to ASCII code. .I size is the length of the string given by .IR buf . e.g.: "foo bar" is encoded as "666F6F20626172". "\\1\\2\\3\\4" is encoded as "01020304". .SH "RETURN VALUE" Returns a encoded string same as .I final or, NULL on error. .SH "SEE ALSO" .BR audit_encode_nv_string (3), .BR audit_value_needs_encoding (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_fgets.3000066400000000000000000000034051501761310600201320ustar00rootroot00000000000000.TH "AUDIT_FGETS" "3" "May 2025" "Red Hat" "Linux Audit API" .SH NAME audit_fgets, audit_fgets_more, audit_fgets_eof, audit_fgets_clear \- buffered line reader helpers .SH SYNOPSIS .B #include .sp .BI "int audit_fgets(char *" buf ", size_t " blen ", int " fd ");" .br .BI "int audit_fgets_more(size_t " blen ");" .br .BI "int audit_fgets_eof(void);" .br .B void audit_fgets_clear(void); .SH DESCRIPTION .B audit_fgets reads from .I fd into .I buf up to .I blen bytes or through the next newline. Text is accumulated across calls in an internal buffer so that complete lines can be returned. The string is NUL terminated. .PP .B audit_fgets_more checks whether the buffer holds a newline or at least .I blen - 1 bytes. .PP .B audit_fgets_eof indicates whether end of file was reached on .I fd . .PP .B audit_fgets_clear resets the internal buffer and EOF state, discarding any stored text. .PP These functions maintain static state and are therefore not thread safe. .SH RETURN VALUE .B audit_fgets returns -1 on error, 0 when no data is available, or the number of characters copied otherwise. .PP .B audit_fgets_more and .B audit_fgets_eof return 1 for true and 0 for false. .PP .B audit_fgets_clear returns no value. .SH BACKGROUND The reason that this family of functions was created is because in auditd plugins, the event stream is stdin, which is descriptor 0. A typical pattern is to call select, poll, or epoll to wait for a record to arrive. As soon as it does, you need to read it. If you use fgets, you will wind up with big problems because you cannot mix low level descriptors with high level constructs like struct FILE. This family of functions allows you to correctly work only using descriptors but with the convenience of fgets. .SH SEE ALSO .BR fgets (3) audit-userspace-4.0.5/docs/audit_flag_to_name.3000066400000000000000000000014261501761310600214360ustar00rootroot00000000000000.TH "AUDIT_FLAG_TO_NAME" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_flag_to_name \- Convert the numeric rule-matching filter value to the rule-matching filter name .SH "SYNOPSIS" .nf .B #include .PP .BI "const char *audit_flag_to_name(int " flag ); .fi .SH "DESCRIPTION" .BR audit_flag_to_name () converts the numeric rule-matching filter value (AUDIT_FILTER_TASK, AUDIT_FILTER_EXIT, AUDIT_FILTER_USER, AUDIT_FILTER_EXCLUDE, AUDIT_FILTER_FS) to the rule-matching filter name ("task", "exit", "user", "exclude", "filesystem"). .I flag is the numeric rule-matching filter value. .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, the return value is the rule-matching filter name. .SH "SEE ALSO" .BR audit_name_to_flag (3), .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_fstype_to_name.3000066400000000000000000000011611501761310600220330ustar00rootroot00000000000000.TH "AUDIT_FSTYPE_TO_NAME" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_fstype_to_name \- Convert the numeric fstype value to the fstype name .SH "SYNOPSIS" .nf .B #include .PP .BI "const char *audit_fstype_to_name(int " fstype ); .fi .SH "DESCRIPTION" .BR audit_fstype_to_name () converts the numeric fstype value (0x64626720 or 0x74726163) to the fstype name ("debugfs" or "tracefs"). .I fstype is the numeric fstype value. .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, the return value is the fstype name. .SH "SEE ALSO" .BR audit_name_to_fstype (3), .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_get_reply.3000066400000000000000000000015551501761310600210200ustar00rootroot00000000000000.TH "AUDIT_GET_REPLY" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_get_reply \- Get the audit system's reply .SH SYNOPSIS .B #include .sp int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek); .SH "DESCRIPTION" This function gets the next data packet sent on the audit netlink socket. This function is usually called after sending a command to the audit system. fd should be an open file descriptor returned by audit_open. rep should be a data structure to put the reply in. block is of type reply_t which is either: GET_REPLY_BLOCKING and GET_REPLY_NONBLOCKING. peek, if non-zero, gets the data without dequeueing it from the netlink socket. .SH "RETURN VALUE" This function returns \-errno on error, 0 if error response received, and positive value on success. .SH "SEE ALSO" .BR audit_open (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_get_session.3000066400000000000000000000013721501761310600213450ustar00rootroot00000000000000.TH "AUDIT_GET_SESSION" "3" "Dec 2016" "Red Hat" "Linux Audit API" .SH NAME audit_get_session \- Get a program's login session id value .SH SYNOPSIS .B #include .sp uin32_t audit_get_session(void); .SH DESCRIPTION This function returns the task's session id attribute. .SH "RETURN VALUE" This function returns the session id value if it was set. It will return a \-1 if the session id is unset. However, since uint32_t is an unsigned type, you will see the converted value instead of \-1. .SH "ERRORS" This function returns \-2 on failure. Additionally, in the event of a real error, errno would be set. The function can set errno based on failures of open, read, or strtoul. .SH "SEE ALSO" .BR audit_getloginuid (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_getloginuid.3000066400000000000000000000013351501761310600213340ustar00rootroot00000000000000.TH "AUDIT_GETLOGINUID" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_getloginuid \- Get a program's loginuid value .SH SYNOPSIS .B #include .sp uid_t audit_getloginuid(void); .SH DESCRIPTION This function returns the task attribute loginuid. .SH "RETURN VALUE" This function returns the loginuid value if it was set. It will return a \-1 if loginuid was unset. However, since uid_t is an unsigned type, you will see the converted value instead of \-1. .SH "ERRORS" This function returns \-1 on failure. However, in the event of a real error, errno would be set. The function can set errno based on failures of open, read, or strtoul. .SH "SEE ALSO" .BR audit_setloginuid (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_is_enabled.3000066400000000000000000000010411501761310600211010ustar00rootroot00000000000000.TH "AUDIT_IS_ENABLED" "3" "May 2021" "Red Hat" "Linux Audit API" .SH NAME audit_is_enabled \- judge whether auditing is enabled or not .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_is_enabled(int " fd "); .fi .SH "DESCRIPTION" .BR audit_is_enabled () judges whether auditing is enabled or not. .I fd must have been returned by .BR audit_open (3). .SH "RETURN VALUE" This function will return 0 if auditing is NOT enabled and 1 if enabled, and -1 on error. .SH "SEE ALSO" .BR audit_set_enabled (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_acct_message.3000066400000000000000000000034151501761310600223020ustar00rootroot00000000000000.TH "AUDIT_LOG_ACCT_MESSAGE" "3" "Nov 2015" "Red Hat" "Linux Audit API" .SH NAME audit_log_acct_message \- log a user account message .SH SYNOPSIS .B #include .sp int audit_log_acct_message(int audit_fd, int type, const char *pgname, const char *op, const char *name, unsigned int id, const char *host, const char *addr, const char *tty, int result) .SH DESCRIPTION This function will log a message to the audit system using a predefined message format. It should be used for all account manipulation operations. The function parameters are as follows: .RS .TP audit_fd - The fd returned by audit_open .TP type - type of message: AUDIT_USER_CHAUTHTOK for changing any account attributes. .TP pgname - program's name, if NULL will attempt to figure out .TP op - operation. Ex: "adding-user", "changing-finger-info", "deleting-group". This value should have a dash or underscore between the words so that report parsers group them together. .TP name - user's account or group name. If not available use NULL. .TP id - uid or gid that the operation is being performed on. If the user is unknown, pass a \-1 and fill in the name parameter. This is used only when user is NULL. .TP host - The hostname if known. If not available pass a NULL. .TP addr - The network address of the user. If not available pass a NULL. .TP tty - The tty of the user, if NULL will attempt to figure out .TP result - 1 is "success" and 0 is "failed" .RE .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_user_comm_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_semanage_message.3000066400000000000000000000036441501761310600231540ustar00rootroot00000000000000.TH "AUDIT_LOG_SEMANAGE_MESSAGE" "3" "Jan 2012" "Red Hat" "Linux Audit API" .SH NAME audit_log_semanage_message \- log a semanage message .SH SYNOPSIS .B #include .sp .B int audit_log_semanage_message(int audit_fd, int type, .B const char *pgname, const char *op, const char *name, unsigned int id, .B const char *new_seuser, const char *new_role, const char *new_range, .B const char *old_seuser, const char *old_role, const char *old_range, .B const char *host, const char *addr, const char *tty, int result) .SH DESCRIPTION This function will log a message to the audit system using a predefined message format. It should be used for all SE Linux user and role manipulation operations. The function parameters are as follows: .nf audit_fd - The fd returned by audit_open type - type of message: AUDIT_ROLE_ASSIGN/REMOVE for changing any SE Linux user or role attributes. pgname - program's name op - operation. "adding-user", "adding-role", "deleting-user", "deleting-role" name - user's account. If not available use NULL. id - uid that the operation is being performed on. This is used only when name is NULL. new_seuser - the new seuser that the login user is getting new_role - the new_role that the login user is getting new_range - the new mls range that the login user is getting old_seuser - the old seuser that the login usr had old_role - the old role that the login user had old_range - the old mls range that the login usr had host - The hostname if known addr - The network address of the user tty - The tty of the user result - 1 is "success" and 0 is "failed" .fi .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_acct_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_user_comm_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_user_avc_message.3000066400000000000000000000024021501761310600231720ustar00rootroot00000000000000.TH "AUDIT_LOG_USER_AVC_MESSAGE" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_log_user_avc_message \- log a user avc message .SH SYNOPSIS .B #include .sp .B int audit_log_user_avc_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, uid_t auid) .SH DESCRIPTION This function will log a message to the audit system using a predefined message format. This function should be used by all apps that are SE Linux object managers. The function parameters are as follows: .nf audit_fd - The fd returned by audit_open type - type of message, ex: AUDIT_USER_AVC message - the message being sent hostname - the hostname if known addr - The network address of the user tty - The tty of the user, if NULL will attempt to figure out auid - The auid of the person related to the avc message .fi These values should correspond to who the message is about. .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_acct_message (3), .BR audit_log_user_comm_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_user_comm_message.3000066400000000000000000000026741501761310600233670ustar00rootroot00000000000000.TH "AUDIT_LOG_USER_COMM_MESSAGE" "3" "July 2016" "Red Hat" "Linux Audit API" .SH NAME audit_log_user_comm_message \- log a user message from a console app .SH SYNOPSIS .B #include .sp int audit_log_user_comm_message(int audit_fd, int type, const char *message, const char *comm, const char *hostname, const char *addr, const char *tty, int result) .SH DESCRIPTION This function will log a message to the audit system using a predefined message format. This function should be used by all non-ELF console apps that do not manipulate accounts, groups, or need to log execution of a script. An example would be a Python script recording an event. The function parameters are as follows: .nf audit_fd - The fd returned by audit_open type - type of message, ex: AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN message - the message text being sent comm - the program command line name, NULL if unknown hostname - the hostname if known, NULL if unknown addr - The network address of the user, NULL if unknown tty - The tty of the user, if NULL will attempt to figure out result - 1 is "success" and 0 is "failed" .fi .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_acct_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_user_command.3000066400000000000000000000022611501761310600223360ustar00rootroot00000000000000.TH "AUDIT_LOG_USER_COMMAND" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME audit_log_user_command \- log a user command .SH SYNOPSIS .B #include .sp .B int audit_log_user_command(int audit_fd, int type, const char *command, const char *tty, int result); .SH DESCRIPTION This function will log a command to the audit system using a predefined message format. It encodes the command as the audit system expects for untrusted strings. This function should be used by all apps need to record commands. The function parameters are as follows: .nf audit_fd - The fd returned by audit_open type - type of message, ex: AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN command - the command being logged tty - The tty of the user, if NULL will attempt to figure out result - 1 is "success" and 0 is "failed" .fi .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_message (3), .BR audit_log_user_comm_message (3), .BR audit_log_acct_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_log_user_message.3000066400000000000000000000025751501761310600223540ustar00rootroot00000000000000.TH "AUDIT_LOG_USER_MESSAGE" "3" "July 2016" "Red Hat" "Linux Audit API" .SH NAME audit_log_user_message \- log a general user message .SH SYNOPSIS .B #include .sp int audit_log_user_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, int result) .SH DESCRIPTION This function will log a message to the audit system using a predefined message format. This function should be used by all ELF console apps that do not manipulate accounts or groups. If the application is written in Python or another interpreter, then use the .I audit_log_user_comm_message function instead. The function parameters are as follows: .nf audit_fd - The fd returned by audit_open type - type of message, ex: AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN message - the message text being sent hostname - the hostname if known, NULL if unknown addr - The network address of the user, NULL if unknown tty - The tty of the user, if NULL will attempt to figure out result - 1 is "success" and 0 is "failed" .fi .SH "RETURN VALUE" It returns the sequence number which is > 0 on success or <= 0 on error. .SH "ERRORS" This function returns \-1 on failure. Examine errno for more info. .SH "SEE ALSO" .BR audit_log_user_comm_message (3), .BR audit_log_acct_message (3), .BR audit_log_user_avc_message (3), .BR audit_log_semanage_message (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_name_to_action.3000066400000000000000000000020131501761310600217730ustar00rootroot00000000000000.TH "AUDIT_NAME_TO_ACTION" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_name_to_action, audit_action_to_name \- Convert the action name to the numeric action value to each other .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_name_to_action(const char " *action ); .PP .BI "const char *audit_action_to_name(int " action ); .fi .SH "DESCRIPTION" .BR audit_name_to_action () converts the action name ("never", "possible", "always") to the numeric action value (AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS). .I action is the action name. .PP .BR audit_action_to_name () converts the numeric action value (AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS) to the action name ("never", "possible", "always"). .I action is the numeric action value .SH "RETURN VALUE" .BR audit_name_to_action () returns -1 if an error occurs; otherwise, the return value is the numeric action value. .PP .BR audit_action_to_name () returns NULL if an error occurs; otherwise, the return value is the action name. .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_name_to_errno.3000066400000000000000000000017351501761310600216550ustar00rootroot00000000000000.TH "AUDIT_NAME_TO_ERRNO" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_name_to_errno, audit_errno_to_name \- Convert the errno name and the numeric errno value to each other .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_name_to_errno(const char " *error ); .PP .BI "const char *audit_errno_to_name(int " error ); .fi .SH "DESCRIPTION" .BR audit_name_to_errno () converts the errno name ("EPERM", "ENOENT", "ESRCH", etc.) to the numeric errno value (EPERM, ENOENT, ESRCH, etc.). .I error is the errno name. .PP .BR audit_errno_to_name () converts the numeric errno value (EPERM, ENOENT, ESRCH, etc.) to the errno name ("EPERM", "ENOENT", "ESRCH", etc.). .I error is the numeric errno value. .SH "RETURN VALUE" .BR audit_name_to_errno () returns 0 if an error occurs; otherwise, the return value is the numeric errno value. .PP .BR audit_errno_to_name () returns NULL if an error occurs; otherwise, the return value is the errno name. .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_name_to_flag.3000066400000000000000000000014241501761310600214340ustar00rootroot00000000000000.TH "AUDIT_NAME_TO_FLAG" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_name_to_flag \- Convert the rule-matching filter name to the numeric rule-matching filter value .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_name_to_flag(const char " *flag ); .fi .SH "DESCRIPTION" .BR audit_name_to_flag () converts the rule-matching filter name ("task", "exit", "user", "exclude", "filesystem") to the numeric rule-matching filter value (AUDIT_FILTER_TASK, AUDIT_FILTER_EXIT, AUDIT_FILTER_USER, AUDIT_FILTER_EXCLUDE, AUDIT_FILTER_FS). .I flag is the rule-matching filter name. .SH "RETURN VALUE" Returns -1 if an error occurs; otherwise, the return value is the numeric rule-matching filter value. .SH "SEE ALSO" .BR audit_flag_to_name (3), .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_name_to_fstype.3000066400000000000000000000011521501761310600220330ustar00rootroot00000000000000.TH "AUDIT_NAME_TO_FSTYPE" "3" "Mar 2022" "Red Hat" "Linux Audit API" .SH NAME audit_name_to_fstype \- Convert the fstype name to the numeric fstype value .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_name_to_fstype(const char " *name ); .fi .SH "DESCRIPTION" .BR audit_name_to_fstype () converts the fstype name ("debugfs" or "tracefs") to the numeric fstype value (0x64626720 or 0x74726163). .I name is the fstype name. .SH "RETURN VALUE" Returns -1 if an name occurs; otherwise, the return value is the numeric fstype value. .SH "SEE ALSO" .BR audit_fstype_to_name (3), .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_name_to_syscall.3000066400000000000000000000013701501761310600221750ustar00rootroot00000000000000.TH "AUDIT_NAME_TO_SYSCALL" "3" "Nov 2021" "Red Hat" "Linux Audit API" .SH NAME audit_name_to_syscall \- Convert the syscall name to the numeric syscall value .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_name_to_syscall(const char " *sc ", int " machine ); .fi .SH "DESCRIPTION" .BR audit_name_to_syscall () converts the syscall name to the numeric syscall value. .I sc is the syscall name. .I machine is the enum value of the machine type defined in machine_t. .I machine can be obtained by calling .BR audit_detect_machine (3). .SH "RETURN VALUE" Returns -1 if an error occurs; otherwise, the return value is the numeric syscall value. .SH "SEE ALSO" .BR audit_syscall_to_name (3), .BR audit_detect_machine (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_open.3000066400000000000000000000014551501761310600177660ustar00rootroot00000000000000.TH "AUDIT_OPEN" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_open \- Open a audit netlink socket connection .SH "SYNOPSIS" .B #include .sp int audit_open(void); .SH "DESCRIPTION" audit_open creates a NETLINK_AUDIT socket for communication with the kernel part of the Linux Audit Subsystem. The audit system uses the ACK feature of netlink. This means that every message to the kernel will return a netlink status packet even if the operation succeeds. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, the return value is a descriptor referencing the socket. .SH ERRORS The .BR audit_open () function may fail and set .I errno for any of the errors specified for the .BR socket (2) and .BR fcntl (2) routines. .SH "SEE ALSO" .BR netlink (7). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_request_rules_list_data.3000066400000000000000000000013371501761310600237520ustar00rootroot00000000000000.TH "AUDIT_REQUEST_RULES_LIST_DATA" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_request_rules_list_data \- Request list of current audit rules .SH "SYNOPSIS" .B #include .sp int audit_request_rules_list_data(int fd); .SH "DESCRIPTION" audit_request_rules_list_data sends a request to the kernel to list the current audit rules. The rules are sent back one after another after this request is issued. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_add_rule_data (3), .BR audit_delete_rule_data (3), .BR audit_open (3), .BR auditctl (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_request_signal_info.3000066400000000000000000000016121501761310600230600ustar00rootroot00000000000000.TH "AUDIT_REQUEST_SIGNAL_INFO" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME audit_request_signal_info \- Request signal info for the audit system .SH "SYNOPSIS" .B #include .sp int audit_request_signal_info(int fd); .SH "DESCRIPTION" audit_request_signal_info requests that the kernel send information about the sender of a signal to the audit daemon. The signal info structure is as follows: .nf struct audit_sig_info { uid_t uid; pid_t pid; char ctx[0]; }; .fi This function is likely to be used only by audit daemons and shouldn't be called by any other kind of program. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_open (3), .BR audit_get_reply (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_request_status.3000066400000000000000000000022171501761310600221150ustar00rootroot00000000000000.TH "AUDIT_REQUEST_STATUS" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_request_status \- Request status of the audit system .SH "SYNOPSIS" .B #include .sp int audit_request_status(int fd); .SH "DESCRIPTION" .PP audit_request_status requests that the kernel send status structure describing various settings. The audit_status structure is as follows: .RS .ta 4n 10n 24n .nf struct audit_status { __u32 mask; /* Bit mask for valid entries */ __u32 enabled; /* 1 = enabled, 0 = disabled */ __u32 failure; /* Failure-to-log action */ __u32 pid; /* pid of auditd process */ __u32 rate_limit; /* messages rate limit (per second) */ __u32 backlog_limit; /* waiting messages limit */ __u32 lost; /* messages lost */ __u32 backlog; /* messages waiting in queue */ }; .fi .ta .RE .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_open (3), .BR audit_get_reply (3), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_backlog_limit.3000066400000000000000000000014571501761310600225020ustar00rootroot00000000000000.TH "AUDIT_SET_BACKLOG_LIMIT" "3" "Oct 2006" "Linux Audit API" .SH NAME audit_set_backlog_limit \- Set the audit backlog limit .SH "SYNOPSIS" .B #include .sp int audit_set_backlog_limit(int fd, uint32_t limit); .SH "DESCRIPTION" audit_set_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. The default value is 64 which can potentially be overrun by bursts of activity. When the backlog limit is reached, the kernel consults the failure_flag to see what action to take. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_set_failure (3), .BR audit_open (3), .BR auditd (8), .BR auditctl (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_backlog_wait_time.3000066400000000000000000000015371501761310600233450ustar00rootroot00000000000000.TH "AUDIT_SET_BACKLOG_WAIT_TIME" "3" "Oct 2014" "Linux Audit API" .SH NAME audit_set_backlog_wait_time \- Set the audit backlog wait time .SH "SYNOPSIS" .B #include .sp int audit_set_backlog_wait_time(int fd, uint32_t bwt); .SH "DESCRIPTION" audit_set_backlog_wait_time sets the time that the kernel will wait before attempting to send more audit events to be transferred to the audit daemon when the backlog_limit is reached. This gives the audit daemon a chance to drain the kernel queue. The default value is 60000 or 60 * HZ setting in the kernel. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_set_backlog_limit (3), .BR audit_open (3), .BR auditd (8), .BR auditctl (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_enabled.3000066400000000000000000000020551501761310600212670ustar00rootroot00000000000000.TH "AUDIT_SET_ENABLED" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_set_enabled \- Enable or disable auditing .SH "SYNOPSIS" .B #include .sp int audit_set_enabled(int fd, uint32_t enabled); .SH "DESCRIPTION" .PP audit_set_enabled is used to control whether or not the audit system is active. When the audit system is enabled (enabled set to 1), every syscall will pass through the audit system to collect information and potentially trigger an event. If the audit system is disabled (enabled set to 0), syscalls do not enter the audit system and no data is collected. There may be some events generated by MAC subsystems like SE Linux even though the audit system is disabled. It is possible to suppress those events, too, by adding an audit rule with flags set to AUDIT_FILTER_EXCLUDE .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_add_rule_data (3), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_failure.3000066400000000000000000000020321501761310600213170ustar00rootroot00000000000000.TH "AUDIT_SET_FAILURE" "3" "June 2015" "Red Hat" "Linux Audit API" .SH NAME audit_set_failure \- Set audit failure flag .SH "SYNOPSIS" .B #include .sp int audit_set_failure(int fd, uint32_t failure); .SH "DESCRIPTION" audit_set_failure sets the action that the kernel will perform when the backlog limit is reached or when it encounters an error and cannot proceed. Possible values are: .TP 0 - AUDIT_FAIL_SILENT Do nothing, report nothing, skip logging the record and continue. .TP 1 - AUDIT_FAIL_PRINTK [default] Log the audit record using printk which will cause subsequent events to get written to syslog. .TP 2 - AUDIT_FAIL_PANIC Call the panic function. This would be used to prevent use of the machine upon loss of audit events. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_set_backlog_limit (3), .BR audit_open (3), .BR auditd (8), .BR auditctl (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_pid.3000066400000000000000000000017261501761310600204550ustar00rootroot00000000000000.TH "AUDIT_SET_PID" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_set_pid \- Set audit daemon process ID .SH "SYNOPSIS" .B #include .sp int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode); .SH "DESCRIPTION" audit_set_pid tells the kernel what the pid is of the audit daemon. When the pid is set to 0, the kernel will log all events to syslog. Otherwise it will try to send events to the netlink connection that has the same pid given by this function. If for some reason the process goes away, the kernel will automatically set the value to 0 itself. Usually this function is called by the audit daemon and not an external program. If wmode is WAIT_YES, the function will wait for an ACK from the kernel. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_open (3), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_set_rate_limit.3000066400000000000000000000013551501761310600220300ustar00rootroot00000000000000.TH "AUDIT_SET_RATE_LIMIT" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_set_rate_limit \- Set audit rate limit .SH "SYNOPSIS" .B #include .sp int audit_set_rate_limit(int fd, uint32_t limit); .SH "DESCRIPTION" audit_set_rate_limit will set the maximum number of messages that the kernel will send per second. This can be used to throttle the rate if systems become unresponsive. Of course the trade off is that events will be dropped. The default value is 0, meaning no limit. .SH "RETURN VALUE" The return value is <= 0 on error, otherwise it is the netlink sequence id number. This function can have any error that sendto would encounter. .SH "SEE ALSO" .BR audit_open (3), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_setloginuid.3000066400000000000000000000016321501761310600213500ustar00rootroot00000000000000.TH "AUDIT_SETLOGINUID" "3" "Oct 2006" "Red Hat" "Linux Audit API" .SH NAME audit_setloginuid \- Set a program's loginuid value .SH SYNOPSIS .B #include .sp int audit_setloginuid(uid_t uid); .SH "DESCRIPTION" This function sets the task attribute loginuid with the value of uid. The loginuid value may only be set by programs with the CAP_AUDIT_CONTROL capability. This normally means the root account. .sp The loginuid value is part of the task structure and is inherited by child processes. It is used to track what account a user gained system access with. All system entry point programs should set this value right before changing to the uid of the user granted access so that audit events are properly attributed to the that user. .SH "RETURN VALUE" This function returns 0 on success and non-zero otherwise. .SH "SEE ALSO" .BR audit_getloginuid (3), .BR pam_loginuid (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_syscall_to_name.3000066400000000000000000000013721501761310600221770ustar00rootroot00000000000000.TH "AUDIT_SYSCALL_TO_NAME" "3" "Nov 2021" "Red Hat" "Linux Audit API" .SH NAME audit_syscall_to_name \- Convert the numeric syscall value to the syscall name .SH "SYNOPSIS" .nf .B #include .PP .BI "const char *audit_syscall_to_name(int " sc ", int " machine ); .fi .SH "DESCRIPTION" .BR audit_syscall_to_name () converts the numeric syscall value to the syscall name. .I sc is the numeric syscall value. .I machine is the enum value of the machine type defined in machine_t. .I machine can be obtained by calling .BR audit_detect_machine (3). .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, the return value is the syscall name. .SH "SEE ALSO" .BR audit_name_to_syscall (3), .BR audit_detect_machine (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_update_watch_perms.3000066400000000000000000000012331501761310600226750ustar00rootroot00000000000000.TH "AUDIT_UPDATE_WATCH_PERMS" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME audit_update_watch_perms \- update permissions field of watch command .SH "SYNOPSIS" .B #include .sp int audit_update_watch_perms(struct audit_rule_data *rule, int perms); .SH "DESCRIPTION" audit_update_watch_perms adds the permission checks to a watch command that is being built. The perms are a bitwise or'ing of: AUDIT_PERM_EXEC, AUDIT_PERM_WRITE, AUDIT_PERM_READ, AUDIT_PERM_ATTR. .SH "RETURN VALUE" Returns a number < 0 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR audit_add_rule_data (3), .BR audit_add_watch (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/audit_value_needs_encoding.3000066400000000000000000000013411501761310600231570ustar00rootroot00000000000000.TH "AUDIT_VALUE_NEEDS_ENCODING" "3" "Apr 2021" "Red Hat" "Linux Audit API" .SH NAME audit_value_needs_encoding \- check a string to see if it needs encoding .SH "SYNOPSIS" .nf .B #include .PP .BI "int audit_value_needs_encoding(const char *" str ", unsigned int " size "); .fi .SH "DESCRIPTION" .BR audit_value_needs_encoding () checks a string to see if it needs encoding. Specifically, this function checks if the string contains a space, a double-quote, or a control character. .I str is the string to check if encoding is needed. .I size is the length of str. .SH "RETURN VALUE" The return value if encoding is needed is 1. If not needed is 0. .SH "SEE ALSO" .BR audit_encode_nv_string (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auditctl.8000066400000000000000000000506201501761310600174530ustar00rootroot00000000000000.TH AUDITCTL "8" "Sep 2023" "Red Hat" "System Administration Utilities" .SH NAME auditctl \- a utility to assist controlling the kernel's audit system .SH SYNOPSIS \fBauditctl\fP [\fIoptions\fP] .SH DESCRIPTION The \fBauditctl\fP program is used to configure kernel options related to auditing, to see status of the configuration, and to load discretionary audit rules. .SH CONFIGURATION OPTIONS .TP .BI \-b\ backlog Set max number (limit) of outstanding audit buffers allowed (Kernel Default=64) If all buffers are full, the failure flag is consulted by the kernel for action. .TP .BI \-\-backlog_wait_time \ \fIwait_time\fP Set the time for the kernel to wait (Kernel Default 60*HZ) when the backlog limit is reached before queuing more audit events to be transferred to auditd. The number must be greater than or equal to zero and less than 10 times the default value. .TP .BI \-\-reset_backlog_wait_time_actual Reset the actual backlog wait time counter shown by the status command. .TP .B \-c Continue loading rules in spite of an error. This summarizes the results of loading the rules. The exit code will not be success if any rule fails to load. .TP .B \-D Delete all rules and watches. This can take a key option (\-k), too. .TP \fB\-e\fP [\fB0\fP..\fB2\fP] Set enabled flag. When \fB0\fP is passed, this can be used to temporarily disable auditing. When \fB1\fP is passed as an argument, it will enable auditing. To lock the audit configuration so that it can't be changed, pass a \fB2\fP as the argument. Locking the configuration is intended to be the last command in audit.rules for anyone wishing this feature to be active. Any attempt to change the configuration in this mode will be audited and denied. The configuration can only be changed by rebooting the machine. .TP \fB\-f\fP [\fB0\fP..\fB2\fP] Set failure mode \fB0\fP=silent \fB1\fP=printk \fB2\fP=panic. This option lets you determine how you want the kernel to handle critical errors. Example conditions where this mode may have an effect includes: transmission errors to userspace audit daemon, backlog limit exceeded, out of kernel memory, and rate limit exceeded. The default value is \fB1\fP. Secure environments will probably want to set this to \fB2\fP. .TP .B \-h Help .TP .B \-i When given by itself, ignore errors when reading rules from a file. This causes auditctl to always return a success exit code. If passed as an argument to .B \-s then it gives an interpretation of the numbers to human readable words if possible. .TP .BI \-\-loginuid-immutable This option tells the kernel to make loginuids unchangeable once they are set. Changing loginuids requires CAP_AUDIT_CONTROL. So, its not something that can be done by unprivileged users. Setting this makes loginuid tamper-proof, but can cause some problems in certain kinds of containers. .TP .BI \-q\ mount-point,subtree If you have an existing directory watch and bind or move mount another subtree in the watched subtree, you need to tell the kernel to make the subtree being mounted equivalent to the directory being watched. If the subtree is already mounted at the time the directory watch is issued, the subtree is automatically tagged for watching. Please note the comma separating the two values. Omitting it will cause errors. .TP .BI \-r\ rate Set limit in messages/sec (\fB0\fP=none). If this \fIrate\fP is non-zero and is exceeded, the failure flag is consulted by the kernel for action. The default value is \fB0\fP. .TP .BI \-\-reset-lost Reset the lost record counter shown by the status command. .TP .BI \-R\ file Read and execute auditctl commands from a \fIfile\fP. The commands are executed line-by-line, in the order that they appear in the file. The file must be owned by root and not readable by other users, or else it will be rejected. Empty lines are skipped. Lines starting with the '#' character are treated as comment lines. Each line is executed as if it was provided to auditctl as command line arguments. Since auditctl is the one reading the file and not a shell such as bash, do not escape special shell characters. See the EXAMPLES section for an example. .TP .BI \-\-signal\ signal Send a signal to the audit daemon. You must have privileges to do this. Supported signals are .I TERM, HUP, USR1, USR2, CONT and user friendly versions .I stop, reload, rotate, resume, state. .TP .BI \-t Trim the subtrees after a mount command. .SH STATUS OPTIONS .TP .B \-l List all rules 1 per line. Two more options may be given to this command. You can give either a key option (\-k) to list rules that match a key or a (\-i) to have a0 through a3 interpreted to help determine the syscall argument values are correct . .TP .BI \-m\ text Send a user space message into the audit system. This can only be done if you have CAP_AUDIT_WRITE capability (normally the root user has this). The resulting event will be the USER type. .TP .B \-s Report the kernel's audit subsystem status. It will tell you the in-kernel values that can be set by \fB-e\fP, \fB-f\fP, \fB-r\fP, and \fB-b\fP options. The pid value is the process number of the audit daemon. Note that a pid of 0 indicates that the audit daemon is not running. The lost entry will tell you how many event records that have been discarded due to the kernel audit queue overflowing. The backlog field tells how many event records are currently queued waiting for auditd to read them. This option can be followed by the \fB-i\fP to get a couple fields interpreted. .TP .BI \-v Print the version of auditctl. .SH RULE OPTIONS .TP .BI \-a\ [ list,action | action,list ] Append rule to the end of \fIlist\fP with \fIaction\fP. Please note the comma separating the two values. Omitting it will cause errors. The fields may be in either order. It could be list,action or action,list. The following describes the valid \fIlist\fP names: .RS .TP 12 .B task Add a rule to the per task list. This rule list is used only at the time a task is created -- when fork() or clone() are called by the parent task. When using this list, you should only use fields that are known at task creation time, such as the uid, gid, etc. .TP .B exit Add a rule to the syscall exit list. This list is used upon exit from a system call to determine if an audit event should be created. .TP .B user Add a rule to the user message filter list. This list is used by the kernel to filter events originating in user space before relaying them to the audit daemon. It should be noted that the only fields that are valid are: uid, auid, gid, pid, subj_user, subj_role, subj_type, subj_sen, subj_clr, msgtype, and executable name. All other fields will be treated as non-matching. It should be understood that any event originating from user space from a process that has CAP_AUDIT_WRITE will be recorded into the audit trail. This means that the most likely use for this filter is with rules that have an action of never since nothing has to be done to allow events to be recorded. .TP .B exclude Add a rule to the event type exclusion filter list. This list is used to filter events that you do not want to see. For example, if you do not want to see any avc messages, you would using this list to record that. Events can be excluded by process ID, user ID, group ID, login user ID, message type, subject context, or executable name. The action is ignored and uses its default of "never". .TP .B filesystem Add a rule that will be applied to a whole filesystem. The filesystem must be identified with a fstype field. Normally this filter is used to exclude any events for a whole filesystem such as tracefs or debugfs. .TP .B io_uring Add a rule to the io_uring syscall filter. Rules against this filter specify the syscall operation using the -S syscall notion explained below. You can add a key field to the rule so that it may be grouped with other rules watching the same underlying syscall. .RE The following describes the valid \fIactions\fP for the rule: .RS .TP 12 .B never No audit records will be generated. This can be used to suppress event generation. In general, you want suppressions at the top of the list instead of the bottom. This is because the event triggers on the first matching rule. .TP .B always Allocate an audit context, always fill it in at syscall entry time, and always write out a record at syscall exit time. .RE .TP .BI \-A\ list , action Add rule to the beginning \fIlist\fP with \fIaction\fP. .TP \fB\-C\fP [\fIf\fP\fB=\fP\fIf\fP | \fIf\fP\fB!=\fP\fIf\fP] Build an inter-field comparison rule: field, operation, field. You may pass multiple comparisons on a single command line. Each one must start with \fB\-C\fP. Each inter-field equation is anded with each other as well as equations starting with \fB\-F\fP to trigger an audit record. There are 2 operators supported - equal, and not equal. Valid fields are: .RS .TP 12 .B auid, uid, euid, suid, fsuid, obj_uid; and gid, egid, sgid, fsgid, obj_gid .RE .RS The two groups of uid and gid cannot be mixed. But any comparison within the group can be made. The obj_uid/gid fields are collected from the object of the event such as a file or directory. .RE .TP .BI \-d\ list , action Delete rule from \fIlist\fP with \fIaction\fP. The rule is deleted only if it exactly matches syscall name(s) and every field name and value. .TP \fB\-F\fP [\fIn\fP\fB=\fP\fIv\fP | \fIn\fP\fB!=\fP\fIv\fP | \fIn\fP\fB<\fP\fIv\fP | \fIn\fP\fB>\fP\fIv\fP | \fIn\fP\fB<=\fP\fIv\fP | \fIn\fP\fB>=\fP\fIv\fP | \fIn\fP\fB&\fP\fIv\fP | \fIn\fP\fB&=\fP\fIv\fP] Build a rule field: name, operation, value. You may have up to 64 fields passed on a single command line. Each one must start with \fB\-F\fP. Each field equation is anded with each other (as well as equations starting with \fB\-C\fP) to trigger an audit record. There are 8 operators supported - equal, not equal, less than, greater than, less than or equal, and greater than or equal, bit mask, and bit test respectively. Bit test will "and" the values and check that they are equal, bit mask just "ands" the values. Fields that take a user ID may instead have the user's name; the program will convert the name to user ID. The same is true of group names. Valid fields are: .RS .TP 12 .B a0, a1, a2, a3 Respectively, the first 4 arguments to a syscall. Note that string arguments are not supported. This is because the kernel is passed a pointer to the string. Triggering on a pointer address value is not likely to work. So, when using this, you should only use on numeric values. This is most likely to be used on platforms that multiplex socket or IPC operations. .TP .B arch The CPU architecture of the syscall. The arch can be found doing 'uname \-m'. If you do not know the arch of your machine but you want to use the 32 bit syscall table and your machine supports 32 bit, you can also use .B b32 for the arch. The same applies to the 64 bit syscall table, you can use .B b64. In this way, you can write rules that are somewhat arch independent because the family type will be auto detected. However, syscalls can be arch specific and what is available on x86_64, may not be available on ppc. The arch directive should precede the \-S option so that auditctl knows which internal table to use to look up the syscall numbers. .TP .B auid The original ID the user logged in with. Its an abbreviation of audit uid. Sometimes its referred to as loginuid. Either the user account text or number may be used. .TP .B devmajor Device Major Number .TP .B devminor Device Minor Number .TP .B dir Full Path of Directory to watch. This will place a recursive watch on the directory and its whole subtree. It can only be used on exit list. See "\fB\-w\fP". .TP .B egid Effective Group ID. May be numeric or the groups name. .TP .B euid Effective User ID. May be numeric or the user account name. .TP .B exe Absolute path to application that while executing this rule will apply to. It supports = and != operators. Note that you can only use this once for each rule. .TP .B exit Exit value from a syscall. If the exit code is an errno, you may use the text representation, too. .TP .B fsgid Filesystem Group ID. May be numeric or the groups name. .TP .B fstype File system type. This is used with the filesystem rule list. The only values supported are debugfs and tracefs. .TP .B fsuid Filesystem User ID. May be numeric or the user account name. .TP .B filetype The target file's type. Can be either file, dir, socket, link, character, block, or fifo. .TP .B gid Group ID. May be numeric or the groups name. .TP .B inode Inode Number .TP .B key Set a filter key on an audit rule. The filter key is an arbitrary string of text that can be up to 31 bytes long. It can uniquely identify the audit records produced by a rule. Typical use is for when you have several rules that together satisfy a security requirement. The key value can be searched on with ausearch so that no matter which rule triggered the event, you can find its results. The key can also be used on delete all (\-D) and list rules (\-l) to select rules with a specific key. You may have more than one key on a rule if you want to be able to search logged events in multiple ways or if you have an auditd plugin that uses a key to aid its analysis. .TP .B msgtype This is used to match the event's record type. It should only be used on the exclude or user filter lists. .TP .B obj_uid Object's UID .TP .B obj_gid Object's GID .TP .B obj_user Resource's SE Linux User .TP .B obj_role Resource's SE Linux Role .TP .B obj_type Resource's SE Linux Type .TP .B obj_lev_low Resource's SE Linux Low Level .TP .B obj_lev_high Resource's SE Linux High Level .TP .B path Insert a watch for the file system object at \fIpath\fP. You cannot insert a watch to the top level directory. This is prohibited by the kernel. Wildcards are not supported either and will generate a warning. The way that watches work is by tracking the inode internally. This can only be used on exit list. .TP .B perm Permission filter for file operations. Supply the access type that a file system watch will trigger on. \fBr\fP=read, \fBw\fP=write, \fBx\fP=execute, \fBa\fP=attribute change. These permissions are not the standard file permissions, but rather the kind of syscall that would do this kind of thing. The read & write syscalls are omitted from this set since they would overwhelm the logs. But rather for reads or writes, the open flags are looked at to see what permission was requested. The perm field can only be used on exit list. You can use this without specifying a syscall and the kernel will select the syscalls that satisfy the access permissions being requested. This also requires supplying an arch parameter before the perm field. This way the kernel can better determine what syscalls are needed. Not supplying an arch will result in .B all system calls being subject to audit. This will lower system performance. .TP .B pers OS Personality Number .TP .B pid Process ID .TP .B ppid Parent's Process ID .TP .B saddr_fam Address family number as found in /usr/include/bits/socket.h. For example, IPv4 would be 2 and IPv6 would be 10. .TP .B sessionid User's login session ID .TP .B subj_user Program's SE Linux User .TP .B subj_role Program's SE Linux Role .TP .B subj_type Program's SE Linux Type .TP .B subj_sen Program's SE Linux Sensitivity .TP .B subj_clr Program's SE Linux Clearance .TP .B sgid Saved Group ID. See getresgid(2) man page. .TP .B success If the exit value is >= 0 this is true/yes otherwise its false/no. When writing a rule, use a 1 for true/yes and a 0 for false/no .TP .B suid Saved User ID. See getresuid(2) man page. .TP .B uid User ID. May be numeric or the user account name. .RE .TP .BI \-k\ key Set a filter key on an audit rule. This is deprecated when used with watches. Convert any watches to the syscall form of rules. It is still valid for use with deleting or listing rules. .TP \fB\-p\fP [\fBr\fP|\fBw\fP|\fBx\fP|\fBa\fP] Describe the permission access type that a file system watch will trigger on. This is deprecated. Convert watches to the syscall form. .TP \fB\-S\fP [\fISyscall name or number\fP|\fBall\fP] Any \fIsyscall name\fP or \fInumber\fP may be used. The word '\fBall\fP' may also be used. If the given syscall is made by a program, then start an audit record. If a field rule is given and no syscall is specified, it will default to all syscalls. You may also specify multiple syscalls in the same rule by using multiple \-S options in the same rule. Doing so improves performance since fewer rules need to be evaluated. Alternatively, you may pass a comma separated list of syscall names. If you are on a bi-arch system, like x86_64, you should be aware that auditctl simply takes the text, looks it up for the native arch (in this case b64) and sends that rule to the kernel. If there are no additional arch directives, IT WILL APPLY TO BOTH 32 & 64 BIT SYSCALLS. This can have undesirable effects since there is no guarantee that any syscall has the same number on both 32 and 64 bit interfaces. You will likely want to control this and write 2 rules, one with arch equal to b32 and one with b64 to make sure the kernel finds the events that you intend. See the arch field discussion for more info. .TP .BI \-w\ path Place a watch on path. If the path is a file, it's almost the same as using the \-F path option on a syscall rule. If the watch is on a directory, it's almost the same as using the \-F dir option on a syscall rule. The \-w form of writing watches is for backwards compatibility and is .B deprecated due to poor system performance. Convert watches of this form to the syscall based form. The only valid options when using a watch are the \-p and \-k. .TP .BI \-W\ path Remove a watch for the file system object at \fIpath\fP. The rule must match exactly. See \fB-d\fP discussion for more info. .SH "PERFORMANCE TIPS" Syscall rules get evaluated for each syscall for every program. If you have 10 syscall rules, every program on your system will delay during a syscall while the audit system evaluates each rule. Too many syscall rules will hurt performance. Try to combine as many as you can whenever the filter, action, key, and fields are identical. For example: .nf .B auditctl \-a always,exit \-F arch=b64 \-S openat \-F success=0 .fi .nf .B auditctl \-a always,exit \-F arch=b64 \-S truncate \-F success=0 .fi could be re-written as one rule: .nf .B auditctl \-a always,exit \-F arch=b64 \-S openat \-S truncate \-F success=0 .fi Also, try to use file system auditing wherever practical. This improves performance. For example, if you were wanting to capture all failed opens & truncates like above, but were only concerned about files in /etc and didn't care about /usr or /sbin, its possible to use this rule: .nf .B auditctl \-a always,exit \-F arch=b64 \-S openat,truncate \-F dir=/etc \-F success=0 .fi This will be higher performance since the kernel will not evaluate it each and every syscall. It will be handled by the filesystem auditing code and only checked on filesystem related syscalls. .SH "EXAMPLES" To see all syscalls made by a specific program: .nf # By pid: .B auditctl \-a always,exit \-S all \-F pid=1005 # By executable path .B auditctl \-a always,exit \-S all \-F exe=/usr/bin/ls .fi To see files opened by a specific user: .nf .B auditctl \-a always,exit \-S openat \-F auid=510 .fi To see unsuccessful openat calls: .nf .B auditctl \-a always,exit \-S openat \-F success=0 .fi To watch a file for changes (2 ways to express): .nf .B auditctl \-w /etc/shadow \-p wa # Note this slows the system .B auditctl \-a always,exit \-F arch=b64 \-F path=/etc/shadow \-F perm=wa .fi To recursively watch a directory for changes (2 ways to express): .nf .B auditctl \-w /etc/ \-p wa # Note this slows the system .B auditctl \-a always,exit \-F arch=b64 \-F dir=/etc/ \-F perm=wa .fi To see if an admin is accessing other user's files: .nf .B auditctl \-a always,exit \-F dir=/home/ \-F uid=0 \-C auid!=obj_uid .fi This is an example rules file: .nf # Remove all existing rules \-D # Never record sudo invocations \-A exclude,always \-F exe=/usr/bin/sudo .fi .SH DISABLED BY DEFAULT On many systems auditd is configured to install an .B -a never,task rule by default. This rule causes every new process to skip all audit rule processing. This is usually done to avoid a small performance overhead imposed by syscall auditing. If you want to use auditd, you need to remove that rule by deleting 10-no-audit.rules and adding 10-base-config.rules to the audit rules directory. If you have defined audit rules that are not matching when they should, check auditctl -l to make sure there is no never,task rule there. .SH FILES .TP .I /etc/audit/audit.rules /etc/audit/audit-stop.rules .SH "SEE ALSO" .BR audit.rules (7), .BR ausearch(8), .BR aureport(8), .BR auditd (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auditd-plugins.5000066400000000000000000000117411501761310600205710ustar00rootroot00000000000000.TH AUDITD-PLUGINS "5" "Jan 2024" "Red Hat" "System Administration Utilities" .SH NAME auditd-plugins \- realtime event receivers .SH DESCRIPTION \fBauditd\fP can multiplex audit events in realtime. It takes audit events and distributes them to child programs that want to analyze events in realtime. When the audit daemon receives a SIGTERM or SIGHUP, it passes that signal to its child processes so that can reload the configuration or terminate. The child programs install a configuration file in a plugins directory which defaults to \fI/etc/audit/plugins.d\fP. This can be controlled by a auditd.conf config option .B plugin_dir if the admin wished to locate plugins somewhere else. But auditd will install its plugins in the default location. The plugin directory will be scanned and every plugin that is active will be started. If the plugin has a problem and exits, it will be started a maximum of .B max_restarts times as found in auditd.conf. Configuration files must be regular files that do not begin with a '.' character, contain at most one '.' character, and have a '.conf' suffix. Files that do not meet these criteria will be skipped. Config file options are given one per line with an equal sign between the keyword and its value. The available options are as follows: .TP .I active The options for this are .IR yes or .IR no. .TP .I direction The option is dictated by the plugin. .IR In or .IR out are the only choices. You cannot make a plugin operate in a way it wasn't designed just by changing this option. This option is to give a clue to the event dispatcher about which direction events flow. NOTE: inbound events are not supported yet. .TP .I path This is the absolute path to the plugin executable. In the case of internal plugins, it would be the name of the plugin. .TP .I type This tells the dispatcher how the plugin wants to be run. There is only one valid option, .IR always , which means the plugin is external and should always be run. The default is always since there are no more builtin plugins. .TP .I args This allows you to pass arguments to the child program. Generally plugins do not take arguments and have their own config file that instructs them how they should be configured. At the moment, there is a limit of 2 args. .TP .I format The valid options for this are .IR binary and .IR string. .IR Binary passes the data exactly as the audit event dispatcher gets it from the audit daemon. The .IR string option tells the dispatcher to completely change the event into a string suitable for parsing with the audit parsing library. The default value is .IR string. .SH NOTE auditd has an internal queue to hold events for plugins. (See the \fIq_depth\fP setting in \fIauditd.conf\fP.) Plugins have to watch for and dequeue events as fast as possible and queue them internally if they can't be immediately processed. If the plugin is not able to dequeue records, the auditd internal queue will get filled. At any time, as root, you can run the following to check auditd's metrics: auditctl --signal cont ; sleep 1 ; cat /var/run/auditd.state If auditd's internal queue fills, it cannot dequeue any events from the kernel backlog. If the kernel's backlog fills, it looks at the value of backlog_wait_time to delay all processes that generate an event to see if there is eventually room to add the event. This will likely be noticed as slowing down various processes on the machine. The kernel's audit subsystem can be checked by running: auditctl -s When tuning the audit system's performance, you'd want to check both kernel and auditd metrics and adjust accordingly. .SH NOTES FOR DEVELOPERS When the audit daemon starts your plugin, you will be running as root. If you do not need root privileges, you should change uid/gid to lower chances of being a target for exploit. If you need to retain capabilities, using \fBlibcap-ng\fP is the simplest way. Your environment is not going to be clean. You are inheriting many attributes from auditd itself. You will need to adjust your \fBsignal mask\fP, \fBsigaction\fP, \fBumask\fP, and \fBenvironmental variables\fP. Look at the auditd man page to see which signals auditd used. Plugins are expected to handle \fBSIGTERM\fP and \fBSIGHUP\fP. You will also inherit the resource limits of auditd. Note that some of these resource limits, such as maximum number of open descriptors, are controlled by systemd. You also inherit auditd's nice value. You might want to adjust that to be sure to keep up with incoming audit events. Auditd will send events to the plugin on it's \fBstdin\fP. The plugin has to keep this descriptor empty so that events don't back up. If you do significant processing of each event, you should add an internal queue to your design in order to keep events flowing. The \fBauparse_feed\fP function is the preferred way to examine whole events if you need to analyze the contents of the events. .SH FILES /etc/auditd/auditd.conf /etc/audit/plugins.d .SH "SEE ALSO" .BR auditd.conf (5), .BR auditd (8), .BR execve(2), .BR auparse_feed(3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auditd.8000066400000000000000000000102271501761310600171130ustar00rootroot00000000000000.TH "AUDITD" "8" "Sept 2021" "Red Hat" "System Administration Utilities" .SH NAME auditd \- The Linux Audit daemon .SH SYNOPSIS .B auditd .RB [ \-f ]\ [ \-l ]\ [ \-n ]\ [ \-s\ disable|enable|nochange ]\ [ \-c\ ] .SH DESCRIPTION \fBauditd\fP is the userspace component to the Linux Auditing System. It's responsible for writing audit records to the disk. Viewing the logs is done with the .B ausearch or .B aureport utilities. Configuring the audit system or loading rules is done with the .B auditctl utility. During startup, the rules in \fI/etc/audit/audit.rules\fP are read by \fBauditctl\fP and loaded into the kernel. Alternately, there is also an .B augenrules program that reads rules located in \fI/etc/audit/rules.d/\fP and compiles them into an audit.rules file. The audit daemon itself has some configuration options that the admin may wish to customize. They are found in the .B auditd.conf file. .SH OPTIONS .TP .B \-f leave the audit daemon in the foreground for debugging. Messages also go to stderr rather than the audit log. .TP .B \-l allow the audit daemon to follow symlinks for config files. .TP .B \-n no fork. This is useful for running off of inittab or systemd. .TP .B \-s=\fIENABLE_STATE\fR specify when starting if auditd should change the current value for the kernel enabled flag. Valid values for ENABLE_STATE are "disable", "enable" or "nochange". The default is to enable (and disable when auditd terminates). The value of the enabled flag may be changed during the lifetime of auditd using 'auditctl \-e'. .TP .B \-c Specify alternate config file directory. Note that this same directory will be passed to the dispatcher. (default: /etc/audit/) .SH SIGNALS .TP .B SIGHUP causes auditd to reconfigure. This means that auditd re-reads the configuration file. If there are no syntax errors, it will proceed to implement the requested changes. If the reconfigure is successful, a DAEMON_CONFIG event is recorded in the logs. If not successful, error handling is controlled by space_left_action, admin_space_left_action, disk_full_action, and disk_error_action parameters in auditd.conf. .TP .B SIGTERM caused auditd to discontinue processing audit events, write a shutdown audit event, and exit. .TP .B SIGUSR1 causes auditd to immediately rotate the logs. It will consult the max_log_file_action to see if it should keep the logs or not. .TP .B SIGUSR2 causes auditd to attempt to resume logging and passing events to plugins. This is usually needed after logging has been suspended or the internal queue is overflowed. Either of these conditions depends on the applicable configuration settings. .TP .B SIGCONT causes auditd to dump a report of internal state to /var/run/auditd.state. .SH EXIT CODES .TP .B 1 Cannot adjust priority, daemonize, open audit netlink, write the pid file, start up plugins, resolve the machine name, set audit pid, or other initialization tasks. .TP .B 2 Invalid or excessive command line arguments .TP .B 4 The audit daemon doesn't have sufficient privilege .TP .B 6 There is an error in the configuration file .SH FILES .B /etc/audit/auditd.conf - configuration file for audit daemon .P .B /etc/audit/audit.rules - audit rules to be loaded at startup .P .B /etc/audit/rules.d/ - directory holding individual sets of rules to be compiled into one file by augenrules. .P .B /etc/audit/plugins.d/ - directory holding individual plugin configuration files. .P .B /etc/audit/audit-stop.rules - These rules are loaded when the audit daemon stops. .P .B /var/run/auditd.state - report about internal state. .SH NOTES A boot param of audit=1 should be added to ensure that all processes that run before the audit daemon starts is marked as auditable by the kernel. Not doing that will make a few processes impossible to properly audit. The audit daemon can receive audit events from other audit daemons via the audisp\-remote plugin. The audit daemon may be linked with tcp_wrappers to control which machines can connect. If this is the case, you can add an entry to hosts.allow and deny. .SH "SEE ALSO" .BR auditd.conf (5), .BR auditd\-plugins (5), .BR ausearch (8), .BR aureport (8), .BR auditctl (8), .BR augenrules (8), .BR audit.rules (7). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auditd.conf.5000066400000000000000000000564211501761310600200420ustar00rootroot00000000000000.TH AUDITD.CONF "5" "June 2025" "Red Hat" "System Administration Utilities" .SH NAME auditd.conf \- audit daemon configuration file .SH DESCRIPTION The file .I /etc/audit/auditd.conf contains configuration information specific to the audit daemon. Each line should contain one configuration keyword, an equal sign, and then followed by appropriate configuration information. All option names and values are case insensitive. The keywords recognized are listed and described below. Each line should be limited to 160 characters or the line will be skipped. You may add comments to the file by starting the line with a '#' character. .TP .I local_events This yes/no keyword specifies whether or not to include local events. Normally you want local events so the default value is yes. Cases where you would set this to no is when you want to aggregate events only from the network. At the moment, this is useful if the audit daemon is running in a container. This option can only be set once at daemon start up. Reloading the config file has no effect. .TP .I log_file This keyword specifies the full path name to the log file where audit records will be stored. It must be a regular file. The default path is .I /var/log/audit/audit.log if not explicitly set. .TP .I write_logs This yes/no keyword determines whether or not to write logs to the disk. Normally you want this so the default is yes. .TP .I log_format The log format describes how the information should be stored on disk. There are 2 options: raw and enriched. If set to .IR RAW , the audit records will be stored in a format exactly as the kernel sends it. The .IR ENRICHED option will resolve all uid, gid, syscall, architecture, and socket address information before writing the event to disk. This aids in making sense of events created on one system but reported/analyzed on another system. The .I NOLOG option is now deprecated. If you were setting this format, now you should set the write_logs option to no. .TP .I log_group This keyword specifies the group that is applied to the log file's permissions. The default is root. The group name can be either numeric or spelled out. .TP .I priority_boost This is a non-negative number that tells the audit daemon how much of a priority boost it should take. The default is 4. No change is 0. .TP .I flush Valid values are .IR none ", " incremental ", " incremental_async ", " data ", and " sync ". If set to .IR none , no special effort is made to flush the audit records to disk. If set to .IR incremental , Then the .I freq parameter is used to determine how often an explicit flush to disk is issued. The .IR incremental_async parameter is very much like .IR incremental except the flushing is done asynchronously for higher performance. The .I data parameter tells the audit daemon to keep the data portion of the disk file sync'd at all times. The .I sync option tells the audit daemon to keep both the data and meta-data fully sync'd with every write to disk. The default value is incremental_async. .TP .I freq This is a non-negative number that tells the audit daemon how many records to write before issuing an explicit flush to disk command. This value is only valid when the .I flush keyword is set to .IR incremental or incremental_async. .TP .I num_logs This keyword specifies the number of log files to keep if rotate is given as the .I max_log_file_action. If the number is < 2, logs are not rotated. This number must be 999 or less. The default is 0 - which means no rotation. As you increase the number of log files being rotated, you may need to adjust the kernel backlog setting upwards since it takes more time to rotate the files. This is typically done in /etc/audit/audit.rules. If log rotation is configured to occur, the daemon will check for excess logs and remove them in effort to keep disk space available. The excess log check is only done on startup and when a reconfigure results in a space check. .TP .I name_format This option controls how computer node names are inserted into the audit event stream. It has the following choices: .IR none ", " hostname ", " fqd ", " numeric ", and " user ". .IR None means that no computer name is inserted into the audit event. .IR hostname is the name returned by the gethostname syscall. The .IR fqd means that it takes the hostname and resolves it with dns for a fully qualified domain name of that machine. .IR Numeric is similar to fqd except it resolves the IP address of the machine. In order to use this option, you might want to test that 'hostname \-i' or 'domainname \-i' returns a numeric address. Also, this option is not recommended if dhcp is used because you could have different addresses over time for the same machine. .IR User is an admin defined string from the name option. The default value is .IR none ". .TP .I name This is the admin defined string that identifies the machine if .IR user is given as the .IR name_format option. .TP .I max_log_file This keyword specifies the maximum file size in megabytes. When this limit is reached, it will trigger a configurable action. The value given must be numeric. .TP .I max_log_file_action This parameter tells the system what action to take when the system has detected that the max file size limit has been reached. Valid values are .IR ignore ", " syslog ", " suspend ", " rotate " and "keep_logs. If set to .IR ignore , the audit daemon does nothing. .IR syslog means that it will issue a warning to syslog. .IR suspend will cause the audit daemon to stop writing records to the disk. The daemon will still be alive. The .IR rotate option will cause the audit daemon to rotate the logs. It should be noted that logs with higher numbers are older than logs with lower numbers. This is the same convention used by the logrotate utility. The .IR keep_logs option is similar to rotate except it does not use the num_logs setting. This prevents audit logs from being overwritten. The effect is that logs accumulate and are not deleted \- which will trigger the .I space_left_action if the volume fills up. This is best used in combination with an external script used to archive logs on a periodic basis. .TP .I verify_email This option determines if the email address given in .IR action_mail_acct is checked to see if the domain name can be resolved. This option must be given before .IR action_mail_acct or the default value of yes will be used. .TP .I action_mail_acct This option should contain a valid email address or alias. Addresses may use RFC 5233 style subaddressing with the '+' character. The allowed characters are alphanumerics, '@', '.', '-', '_', and '+'. The default address is root. If the email address is not local to the machine, you must make sure you have email properly configured on your machine and network. This this option requires that /usr/lib/sendmail exists on the machine. Many clients provide it as a symlink. .TP .I space_left If the free space in the filesystem containing .IR log_file drops below this value, the audit daemon takes the action specified by .IR space_left_action . If the value of .IR space_left is specified as a whole number, it is interpreted as an absolute size in megabytes (MiB). If the value is specified as a number between 1 and 99 followed by a percentage sign (e.g., 5%), the audit daemon calculates the absolute size in megabytes based on the size of the filesystem containing .IR log_file . (E.g., if the filesystem containing .IR log_file is 2 gigabytes in size, and .IR space_left is set to 25%, then the audit daemon sets .IR space_left to approximately 500 megabytes. Note that this calculation is performed when the audit daemon starts, so if you resize the filesystem containing .IR log_file while the audit daemon is running, you should send the audit daemon SIGHUP to re-read the configuration file and recalculate the correct percentage. .TP .I space_left_action This parameter tells the system what action to take when the system has detected that it is starting to get low on disk space. Valid values are .IR ignore ", " syslog ", " rotate ", " email ", " exec ", " suspend ", and " single . If set to .IR ignore , the audit daemon does nothing. .I syslog means that it will issue a warning to syslog. .I rotate will rotate logs, losing the oldest to free up space. .I Email means that it will send a warning to the email account specified in .I action_mail_acct as well as sending the message to syslog. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. The script is also responsible for telling the auditd daemon to resume logging once its completed its action. This can be done by adding service auditd resume to the script. .I suspend will cause the audit daemon to stop writing records to the disk. The daemon will still be alive. The .I single option will cause the audit daemon to put the computer system in single user mode. Except for rotate, it will perform this action just one time. The previously available .I halt option, which would cause the audit daemon to shut down the computer system, has been deprecated and should no longer be used. It was determined that halting the system at this stage could lead to unintended consequences and is considered a bad action if selected. Disk space notifications follow a three-stage progression. The .I space_left_action is the low water mark and serves as the first warning that disk space is running low. Halting at this stage is not recommended, as it prevents administrators from taking corrective action. The next stage, .I admin_space_left_action, indicates an emergency level where immediate action is required to free up disk space. Administrators should configure critical responses for this level. Finally, the .I disk_full_action occurs when the disk is completely full. At this stage, the system may have already halted, and preemptive measures configured in earlier stages will determine the system’s behavior. .TP .I admin_space_left This is a numeric value in megabytes that tells the audit daemon when to perform a configurable action because the system .B is running low on disk space. This should be considered the last chance to do something before running out of disk space. The numeric value for this parameter should be lower than the number for space_left. You may also append a percent sign (e.g. 1%) to the number to have the audit daemon calculate the number based on the disk partition size. .TP .I admin_space_left_action This parameter tells the system what action to take when the system has detected that it .B is low on disk space. Valid values are .IR ignore ", " syslog ", "rotate ", " email ", " exec ", " suspend ", " single ", and " halt . If set to .IR ignore , the audit daemon does nothing. .I Syslog means that it will issue a warning to syslog. .I rotate will rotate logs, losing the oldest to free up space. .I Email means that it will send a warning to the email account specified in .I action_mail_acct as well as sending the message to syslog. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. The script is also responsible for telling the auditd daemon to resume logging once its completed its action. This can be done by adding service auditd resume to the script. .I Suspend will cause the audit daemon to stop writing records to the disk. The daemon will still be alive. The .I single option will cause the audit daemon to put the computer system in single user mode. The .I halt option will cause the audit daemon to shutdown the computer system. Except for rotate, it will perform this action just one time. .TP .I disk_full_action This parameter tells the system what action to take when the system has detected that the partition to which log files are written has become full. Valid values are .IR ignore ", " syslog ", " rotate ", " exec ", " suspend ", " single ", and " halt . If set to .IR ignore , the audit daemon will issue a syslog message but no other action is taken. .I Syslog means that it will issue a warning to syslog. .I rotate will rotate logs, losing the oldest to free up space. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. The script is also responsible for telling the auditd daemon to resume logging g once its completed its action. This can be done by adding service auditd resume to the script. .I Suspend will cause the audit daemon to stop writing records to the disk. The daemon will still be alive. The .I single option will cause the audit daemon to put the computer system in single user mode. .I halt option will cause the audit daemon to shutdown the computer system. .TP .I disk_error_action This parameter tells the system what action to take whenever there is an error detected when writing audit events to disk or rotating logs. Valid values are .IR ignore ", " syslog ", " exec ", " suspend ", " single ", and " halt . If set to .IR ignore , the audit daemon will not take any action. .I Syslog means that it will issue no more than 5 consecutive warnings to syslog. .I exec /path-to-script will execute the script. You cannot pass parameters to the script. .I Suspend will cause the audit daemon to stop writing records to the disk. The daemon will still be alive. The .I single option will cause the audit daemon to put the computer system in single user mode. .I halt option will cause the audit daemon to shutdown the computer system. .TP .I tcp_listen_port This is a numeric value in the range 1..65535 which, if specified, causes auditd to listen on the corresponding TCP port for audit records from remote systems. The audit daemon may be linked with tcp_wrappers. You may want to control access with an entry in the hosts.allow and deny files. If this is deployed on a systemd based OS, then you may need to adjust the 'After' directive. See the note in the auditd.service file. .TP .I tcp_listen_queue This is a numeric value which indicates how many pending (requested but unaccepted) connections are allowed. The default is 5. Setting this too small may cause connections to be rejected if too many hosts start up at exactly the same time, such as after a power failure. This setting is only used for aggregating servers. Clients logging to a remote server should keep this commented out. .TP .I tcp_max_per_addr This is a numeric value which indicates how many concurrent connections from one IP address is allowed. The default is 1 and the maximum is 1024. Setting this too large may allow for a Denial of Service attack on the logging server. Also note that the kernel has an internal maximum that will eventually prevent this even if auditd allows it by config. The default should be adequate in most cases unless a custom written recovery script runs to forward unsent events. In this case you would increase the number only large enough to let it in too. .TP .I use_libwrap This setting determines whether or not to use tcp_wrappers to discern connection attempts that are from allowed machines. Legal values are either .IR yes ", or " no " The default value is yes. .TP .I tcp_client_ports This parameter may be a single numeric value or two values separated by a dash (no spaces allowed). It indicates which client ports are allowed for incoming connections. If not specified, any port is allowed. Allowed values are 1..65535. For example, to require the client use a privileged port, specify .I 1\-1023 for this parameter. You will also need to set the local_port option in the audisp-remote.conf file. Making sure that clients send from a privileged port is a security feature to prevent log injection attacks by untrusted users. .TP .I tcp_client_max_idle This parameter indicates the number of seconds that a client may be idle (i.e. no data from them at all) before auditd complains. This is used to close inactive connections if the client machine has a problem where it cannot shutdown the connection cleanly. Note that this is a global setting, and must be higher than any individual client heartbeat_timeout setting, preferably by a factor of two. The default is zero, which disables this check. .TP .I transport If set to .IR TCP ", only clear text tcp connections will be used. If set to .IR KRB5 ", then Kerberos 5 will be used for authentication and encryption. The default value is TCP. .TP .I enable_krb5 This option is deprecated. Use the .IR transport option above instead. If set to "yes", Kerberos 5 will be used for authentication and encryption. The default is "no". If this option is set to "yes" and it follows the transport option, it will override the transport setting. This would be the normal expected behavior for backwards compatibility. .TP .I krb5_principal This is the principal for this server. The default is "auditd". Given this default, the server will look for a key named like .I auditd/hostname@EXAMPLE.COM stored in .I /etc/audit/audit.key to authenticate itself, where hostname is the canonical name for the server's host, as returned by a DNS lookup of its IP address. .TP .I krb5_key_file Location of the key for this client's principal. Note that the key file must be owned by root and mode 0400. The default is .I /etc/audit/audit.key .TP .I distribute_network If set to "yes", network originating events will be distributed to the audit dispatcher for processing. The default is "no". .TP .I q_depth This is a numeric value that tells how big to make the internal queue of the audit event dispatcher. A bigger queue lets it handle a flood of events better, but could hold events that are not processed when the daemon is terminated. If you get messages in syslog about events getting dropped, increase this value. The default value is 2000. .TP .I overflow_action This option determines how the daemon should react to overflowing its internal queue. When this happens, it means that more events are being received than it can pass along to child processes. This error means that it is going to lose the current event that it's trying to dispatch. This option has the following choices: .IR ignore ", " syslog ", " suspend ", " single ", and " halt ". If set to .IR ignore , the audit daemon does nothing. .I syslog means that it will issue a warning to syslog. .I suspend will cause the audit daemon to stop sending events to child processes. The daemon will still be alive. The .I single option will cause the audit daemon to put the computer system in single user mode. .I halt option will cause the audit daemon to shutdown the computer system. .TP .I max_restarts This is a non-negative number that tells the audit event dispatcher how many times it can try to restart a crashed plugin. The default is 10. .TP .I plugin_dir This is the location that auditd will use to search for its plugin configuration files. The default directory is .I /etc/audit/plugins.d . .TP .I end_of_event_timeout This is a non-negative number of seconds used by the userspace .I auparse() library routines and the .I aureport(8) , .I ausearch(8) utilities to consider an event is complete when parsing an event log stream. For an event stream being processed, if the time of the current event is over .I end_of_event_timeout seconds old, compared to co-located events, then the event is considered complete. The default is 2 seconds. See the NOTES section for more detail. .TP .I report_interval This option specifies the interval between automatic state reports. The value is a time string composed of a number optionally followed by .B m for minutes, .B h for hours, .B d for days, or .B M for months. The default is 0 which disables preriodic reporting. The largest value is 40 days. When set, auditd will periodically generate the state report written to .I /var/run/auditd.state. .SH RELOADING Most parameters can be changed while the daemon is running by sending .B SIGHUP to .BR auditd . This can also be done with .BR auditctl\ \-\-signal\ reload . Options that are only read at startup include .I local_events and .I verify_email . .SH NOTES In a CAPP environment, the audit trail is considered so important that access to system resources must be denied if an audit trail cannot be created. In this environment, it would be suggested that /var/log/audit be on its own partition. This is to ensure that space detection is accurate and that no other process comes along and consumes part of it. .PP The flush parameter should be set to sync or data. .PP Max_log_file and num_logs need to be adjusted so that you get complete use of your partition. It should be noted that the more files that have to be rotated, the longer it takes to get back to receiving audit events. Max_log_file_action should be set to keep_logs. .PP Space_left should be set to a number that gives the admin enough time to react to any alert message and perform some maintenance to free up disk space. This would typically involve running the \fBaureport \-t\fP report and moving the oldest logs to an archive area. The value of space_left is site dependent since the rate at which events are generated varies with each deployment. The space_left_action is recommended to be set to email. If you need something like an snmp trap, you can use the exec option to send one. .PP Admin_space_left should be set to the amount of disk space on the audit partition needed for admin actions to be recorded. Admin_space_left_action would be set to single so that use of the machine is restricted to just the console. .PP The disk_full_action is triggered when no more room exists on the partition. All access should be terminated since no more audit capability exists. This can be set to either single or halt. .PP The disk_error_action should be set to syslog, single, or halt depending on your local policies regarding handling of hardware malfunctions. .PP Specifying a single allowed client port may make it difficult for the client to restart their audit subsystem, as it will be unable to recreate a connection with the same host addresses and ports until the connection closure TIME_WAIT state times out. .PP Auditd events are made up of one or more records. The auditd system cannot guarantee that the set of records that make up an event will occur atomically, that is the stream will have interleaved records of different events, IE .PP .RS .br event0_record0 .br event1_record0 .br event2_record0 .br event1_record3 .br event2_record1 .br event1_record4 .br event3_record0 .br .RE .PP The auditd system does not guarantee that the records that make up an event will appear in order. Thus, when processing event streams, we need to maintain a list of events with their own list of records hence List of List (LOL) event processing. When processing an event stream we define the end of an event via .P .RS record type = AUDIT_EOE (audit end of event type record), or .br record type = AUDIT_PROCTITLE (we note the AUDIT_PROCTITLE is always the last record), or .br record type = AUDIT_KERNEL (kernel events are one record events), or .br record type < AUDIT_FIRST_EVENT (only single record events appear before this type), or .br record type >= AUDIT_FIRST_ANOM_MSG (only single record events appear after this type), or .br record type >= AUDIT_MAC_UNLBL_ALLOW && record type <= AUDIT_MAC_CALIPSO_DEL (these are also one record events), or .br for the stream being processed, the time of the event is over end_of_event_timeout seconds old. .RE .SH LOG ROTATION POLICY By default, auditd uses size-based log rotation. If you prefer time-based rotation (e.g., hourly, daily, weekly, or custom schedule), refer to auditd.cron(5) for configuration details. .SH FILES .TP .I /etc/audit/auditd.conf Audit daemon configuration file .SH "SEE ALSO" .BR auditd (8), .BR audisp\-remote.conf (5), .BR auditd\-plugins (5), .BR auditd.cron (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auditd.cron.5000066400000000000000000000034431501761310600200520ustar00rootroot00000000000000.TH AUDITD.CRON "5" "Feb 2025" "Red Hat" "System Administration Utilities" .SH NAME auditd.conf \- time-based rotation of audit logs .SH DESCRIPTION By default, the audit daemon (auditd) supports size-based log rotation, where logs are rotated once they reach a specified size, as configured in .I /etc/audit/auditd.conf. This manual describes an alternative method: time-based log rotation using .B cron. Using this approach, audit logs can be rotated at specified intervals (hourly, daily, weekly or on a custom date), regardless of their size. .SH CONFIGURATION .B 1.Disable Size-Based Rotation: To enable time-based log rotation, first disable \fBauditd's\fP built-in size-based rotation by setting the following parameter in .I /etc/audit/auditd.conf: .RS max_log_file_action = ignore .RE .B 2. Configure Log Retention: The .B num_logs parameter determines the number of rotated log files to keep. For daily rotation, setting .RS num_logs = 7 .RE ensures that logs from the last seven days are retained. However, on busy systems, audit logs may grow rapidly, potentially leading to a lack of disk space. To prevent this, ensure that the .B space_left_action parameter is configured to handle low-disk-space situations appropriately. .B 3. Apply Configuration Changes: After modifying the main auditd configuration file, reload auditd to apply the changes: .RS auditctl --signal reload .RE .B 4. Deploy the Rotation Script: Copy the provided .B auditd.cron script to the appropriate cron directory ( .IR cron.daily or .IR cron.hourly or .IR cron.weekly , depending on your rotation preference). Then, ensure the file has the correct SELinux labels: .RS cp /usr/share/doc/audit/auditd.cron /etc/cron.daily .RE .SH "SEE ALSO" .BR auditd.conf (5), .BR auditd (8), .BR cron(8). .SH AUTHOR Attila Lakatos audit-userspace-4.0.5/docs/augenrules.8000066400000000000000000000030451501761310600200130ustar00rootroot00000000000000.TH AUGENRULES "8" "Apr 2013" "Red Hat" "System Administration Utilities" .SH NAME augenrules \- a script that merges component audit rule files .SH SYNOPSIS .B augenrules .RI [ \-\-check ]\ [ \-\-load ] .SH DESCRIPTION \fBaugenrules\fP is a script that merges all component audit rules files, found in the audit rules directory, \fI/etc/audit/rules.d\fP, placing the merged file in \fI/etc/audit/audit.rules\fP. Component audit rule files, must end in \fI.rules\fP in order to be processed. All other files in \fI/etc/audit/rules.d\fP are ignored. .P The files are concatenated in order, based on their natural sort (see -v option of ls(1)) and stripped of empty and comment (#) lines. .P The last processed -\fID\fP directive without an option, if present, is always emitted as the first line in the resultant file. Those with an option are replicated in place. The last processed -\fIb\fP directive, if present, is always emitted as the second line in the resultant file. The last processed -\fIf\fP directive, if present, is always emitted as the third line in the resultant file. The last processed -\fIe\fP directive, if present, is always emitted as the last line in the resultant file. .P The generated file is only copied to \fI/etc/audit/audit.rules\fP, if it differs. .SH OPTIONS .TP .B \-\-check test if rules have changed and need updating without overwriting audit.rules. .TP .B \-\-load load old or newly built rules into the kernel. .SH FILES /etc/audit/rules.d/ /etc/audit/audit.rules .SH "SEE ALSO" .BR audit.rules (7), .BR auditctl (8), .BR auditd (8). audit-userspace-4.0.5/docs/auparse_add_callback.3000066400000000000000000000031541501761310600217210ustar00rootroot00000000000000.TH "AUPARSE_ADD_CALLBACK" "3" "May 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_add_callback \- add a callback handler for notifications .SH "SYNOPSIS" .B #include .sp .nf .B void auparse_add_callback(auparse_state_t *au, auparse_callback_ptr callback, void *user_data, user_destroy user_destroy_func); .fi .SH "DESCRIPTION" auparse_add_callback adds a callback function to the parse state which is invoked to notify the application of parsing events. This is part of the event feed API. The signature of the callback is: .nf void auparse_callback(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data); .fi When the callback is invoked it is passed: .TP .I au a pointer to the parse_state .TP .I cb_event_type enumerated value indicating the reason why the callback was invoked .TP .I user_data pointer to user supplied private data. May be NULL. . .TP .I user_destroy_func pointer to function called when user_data is destroyed. May be NULL. The signature is: .br .sp .nf void destroy(void *user_data); .fi .br .sp The destroy() function should be prepared to accept user_data possibly being NULL. .PP The .I cb_event_type argument indicates why the callback was invoked. It's possible values are: .br .TP .B AUPARSE_CB_EVENT_READY A complete event has been parsed and is ready to be examined. This is logically equivalent to the parse state immediately following .I auparse_next_event() .PP See auparse_feed(3) for a complete code example. . .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR auparse_feed (3), .BR auparse_flush_feed (3). .SH AUTHOR John Dennis audit-userspace-4.0.5/docs/auparse_destroy.3000066400000000000000000000012651501761310600210470ustar00rootroot00000000000000.TH "AUPARSE_DESTROY" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_destroy \- release instance of parser .SH "SYNOPSIS" .B #include .sp .B void auparse_destroy(auparse_state_t *au); .B void auparse_destroy_ext(auparse_state_t *au, auparse_destroy_what_t what); .SH "DESCRIPTION" .B auparse_destroy frees all data structures and closes file descriptors. .B auparse_destroy_ext frees data structures based on what. What can be AUPARSE_DESTROY_ALL to release everything or AUPARSE_DESTROY_COMMON to release everything but the uid and gid lookup cache. .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR auparse_init (3), .BR auparse_reset (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_feed.3000066400000000000000000000061161501761310600202610ustar00rootroot00000000000000.TH "AUPARSE_FEED" "3" "Sept 2023" "Red Hat" "Linux Audit API" .SH NAME auparse_feed \- feed data into parser .SH "SYNOPSIS" .B #include .sp .nf int auparse_feed(auparse_state_t *au, const char *data, size_t data_len); .fi .TP .I au The audit parse state .TP .I data a buffer of data to feed into the parser, it is .I data_len bytes long. The data is copied in the parser, upon return the caller may free or reuse the data buffer. .TP .I data_len number of bytes in .I data .SH "DESCRIPTION" .I auparse_feed supplies new data for the parser to consume. .I auparse_init() must have been called with a source type of AUSOURCE_FEED and a NULL pointer. .br .sp The parser consumes as much data as it can invoking a user supplied callback specified with .I auparse_add_callback with a cb_event_type of .I AUPARSE_CB_EVENT_READY each time the parser recognizes a complete event in the data stream. Data not fully parsed will persist and be prepended to the next feed data. After all data has been feed to the parser .I auparse_flush_feed should be called to signal the end of input data and flush any pending parse data through the parsing system. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "EXAMPLE" .nf void auparse_callback(auparse_state_t *au, auparse_cb_event_t cb_event_type, void *user_data) { int *event_cnt = (int *)user_data; if (cb_event_type == AUPARSE_CB_EVENT_READY) { if (auparse_first_record(au) <= 0) return; printf("event: %d\\n", *event_cnt); printf("records:%d\\n", auparse_get_num_records(au)); do { printf("fields:%d\\n", auparse_get_num_fields(au)); printf("type=%d ", auparse_get_type(au)); const au_event_t *e = auparse_get_timestamp(au); if (e == NULL) return; printf("event time: %lu.%u:%lu\\n", (long unsigned)e\->sec, e\->milli, e\->serial); auparse_first_field(au); do { printf("%s=%s (%s)\\n", auparse_get_field_name(au), auparse_get_field_str(au), auparse_interpret_field(au)); } while (auparse_next_field(au) > 0); printf("\\n"); } while(auparse_next_record(au) > 0); (*event_cnt)++; } } main(int argc, char **argv) { char *filename = argv[1]; FILE *fp; char buf[256]; size_t len; int *event_cnt = malloc(sizeof(int)); au = auparse_init(AUSOURCE_FEED, 0); auparse_set_eoe_timeout(2); *event_cnt = 1; auparse_add_callback(au, auparse_callback, event_cnt, free); if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "could not open '%s', %s\\n", filename, strerror(errno)); return 1; } while ((len = fread(buf, 1, sizeof(buf), fp))) { auparse_feed(au, buf, len); } auparse_flush_feed(au); auparse_destroy(au); } .fi .SH "SEE ALSO" .BR auparse_add_callback (3), .BR auparse_flush_feed (3), .BR auparse_feed_age_events (3), .BR auparse_feed_has_data (3), .BR auparse_metrics (3) .SH AUTHOR John Dennis audit-userspace-4.0.5/docs/auparse_feed_age_events.3000066400000000000000000000011161501761310600224540ustar00rootroot00000000000000.TH "AUPARSE_FEED_AGE_EVENTS" "3" "Apr 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_feed_age_events \- check events for complete based on time. .SH "SYNOPSIS" .B #include .sp void auparse_feed_age_events(auparse_state_t *au); .SH "DESCRIPTION" .I auparse_feed_age_events should be called to see if any events are complete based on the current clock time. Any newly complete events will be passed to the callback function. .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR auparse_feed (3), .BR auparse_flush_feed (3), .BR auparse_feed_has_data (3) .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_feed_has_data.3000066400000000000000000000011221501761310600220750ustar00rootroot00000000000000.TH "AUPARSE_FEED_HAS_DATA" "3" "Apr 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_feed_has_data \- check if there is any data accumulating that might need flushing. .SH "SYNOPSIS" .B #include .sp int auparse_feed_has_data(const auparse_state_t *au); .SH "DESCRIPTION" .I auparse_feed_has_data may be called to determine if there is any records that are accumulating but not yet ready to emit. .SH "RETURN VALUE" Returns 1 if any records are accumulating otherwise 0 if empty. .SH "SEE ALSO" .BR auparse_feed (3), .BR auparse_feed_age_events (3) .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_find_field.3000066400000000000000000000016451501761310600214430ustar00rootroot00000000000000.TH "AUPARSE_FIND_FIELD" "3" "June 2021" "Red Hat" "Linux Audit API" .SH NAME auparse_find_field \- search for field name .SH "SYNOPSIS" .B #include .sp const char *auparse_find_field(auparse_state_t *au, const char *name); .SH "DESCRIPTION" auparse_find_field will scan all records in an event to find the first occurrence of the field name passed to it. Searching begins from the cursor's current position. The field name is stored for subsequent searching. NOTE: auparse creates 2 pseudo fields that do not exist in the natural record for SELinux AVC and USER_AVC decision and permissions. The field names are seresult and seperms respectively. .SH "RETURN VALUE" Returns NULL field not found. If an error occurs errno will be set. Otherwise, it returns a pointer to the text value associated with the field. .SH "SEE ALSO" .BR auparse_first_record (3), .BR auparse_find_field_next (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_find_field_next.3000066400000000000000000000013171501761310600224750ustar00rootroot00000000000000.TH "AUPARSE_FIND_FIELD_NEXT" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_find_field_next \- find next occurrence of field name .SH "SYNOPSIS" .B #include .sp const char *auparse_find_field_next(const auparse_state_t *au); .SH "DESCRIPTION" auparse_find_field_next finds the next occurrence of the previously stored field name. It will scan until it reaches the last record of the current event. .SH "RETURN VALUE" Returns NULL field not found. If an error occurs errno will be set. Otherwise, it returns a pointer to the text value associated with the field. .SH "SEE ALSO" .BR auparse_first_record (3), .BR auparse_next_event (3), .BR auparse_find_field (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_first_field.3000066400000000000000000000010171501761310600216430ustar00rootroot00000000000000.TH "AUPARSE_FIRST_FIELD" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_first_field \- reposition field cursor .SH "SYNOPSIS" .B #include .sp int auparse_first_field(const auparse_state_t *au); .SH "DESCRIPTION" auparse_first_field repositions the library's internal cursor to point to the first field of the current record in the current event. .SH "RETURN VALUE" Returns 0 if there is no event data; otherwise, 1 for success. .SH "SEE ALSO" .BR auparse_next_field (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_first_record.3000066400000000000000000000011061501761310600220350ustar00rootroot00000000000000.TH "AUPARSE_FIRST_RECORD" "3" "Sep 2014" "Red Hat" "Linux Audit API" .SH NAME auparse_first_record \- reposition record cursor .SH "SYNOPSIS" .B #include .sp int auparse_first_record(auparse_state_t *au); .SH "DESCRIPTION" auparse_first_record repositions the internal cursors of the parsing library to point to the first field of the first record in the current event. .SH "RETURN VALUE" Returns \-1 if an error occurs, 0 if there is no event data, or 1 for success. .SH "SEE ALSO" .BR auparse_next_event (3), .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_flush_feed.3000066400000000000000000000011251501761310600214550ustar00rootroot00000000000000.TH "AUPARSE_FLUSH_FEED" "3" "Apr 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_flush_feed \- flush any unconsumed feed data through parser. .SH "SYNOPSIS" .B #include .sp int auparse_flush_feed(auparse_state_t *au); .SH "DESCRIPTION" .I auparse_flush_feed should be called to signal the end of feed input data and flush any pending parse data through the parsing system. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR auparse_feed (3), .BR auparse_feed_age_events (3), .BR auparse_feed_has_data (3) .SH AUTHOR John Dennis audit-userspace-4.0.5/docs/auparse_get_field_int.3000066400000000000000000000010621501761310600221450ustar00rootroot00000000000000.TH "AUPARSE_GET_FIELD_INT" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_field_int \- get current field's value as an int .SH "SYNOPSIS" .B #include .sp int auparse_get_field_int(auparse_state_t *au); .SH "DESCRIPTION" auparse_get_field_int allows access to the value as an int of the current field of the current record in the current event. .SH "RETURN VALUE" Returns \-1 if there is an error with errno set appropriately or the value if errno is zero. .SH "SEE ALSO" .BR auparse_get_field_str (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_field_name.3000066400000000000000000000011221501761310600222700ustar00rootroot00000000000000.TH "AUPARSE_GET_FIELD_NAME" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_field_name \- get current field's name .SH "SYNOPSIS" .B #include .sp const char *auparse_get_field_name(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_field_name allows access to the current field name of the current record in the current event. .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, a pointer to the field's name. .SH "SEE ALSO" .BR auparse_get_field_str (3), .BR auparse_interpret_field (3), .BR auparse_next_field (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_field_num.3000066400000000000000000000013121501761310600221500ustar00rootroot00000000000000.TH "AUPARSE_GET_FIELD_NUM" "3" "Dec 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_get_field_num \- get current field cursor location .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_field_num(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_field_num will retrieve the internal library cursors current field location in the current record. Fields within the same record are numbered starting from 0. This is generally not needed but there are some cases where one may want to know the exact field being looked at. .SH "RETURN VALUE" Returns the current field cursor location. .SH "SEE ALSO" .BR auparse_goto_field_num (3), auparse_get_record_num (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_field_str.3000066400000000000000000000011701501761310600221630ustar00rootroot00000000000000.TH "AUPARSE_GET_FIELD_STR" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_field_str \- get current field's value .SH "SYNOPSIS" .B #include .sp const char *auparse_get_field_str(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_field_str allows access to the value in the current field of the current record in the current event. .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, a pointer to the field's value. .SH "SEE ALSO" .BR auparse_get_field_name (3), .BR auparse_get_field_int (3), .BR auparse_interpret_field (3), .BR auparse_next_field (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_field_type.3000066400000000000000000000014131501761310600223340ustar00rootroot00000000000000.TH "AUPARSE_GET_FIELD_TYPE" "3" "Sept 2008" "Red Hat" "Linux Audit API" .SH NAME auparse_get_field_type \- get current field's data type .SH "SYNOPSIS" .B #include .sp int auparse_get_field_type(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_field_type returns a value from the auparse_type_t enum that describes the kind of data in the current field of the current record in the current event. .SH "RETURN VALUE" Returns AUPARSE_TYPE_UNCLASSIFIED if the field's data type has no known description or is an integer. Otherwise it returns another enum. Fields with the type AUPARSE_TYPE_ESCAPED must be interpreted to access their value since those field's raw value is encoded. .SH "SEE ALSO" .BR auparse_get_field_name (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_filename.3000066400000000000000000000012071501761310600217710ustar00rootroot00000000000000.TH "AUPARSE_GET_FILENAME" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_filename \- get the filename where record was found .SH "SYNOPSIS" .B #include .sp const char *auparse_get_filename(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_filename will return the name of the source file where the record was found if the source type is AUSOURCE_FILE or AUSOURCE_FILE_ARRAY. For other source types the return value will be NULL. .SH "RETURN VALUE" Returns pointer to a filename or NULL if unavailable. .SH "SEE ALSO" .BR auparse_get_line_number (3). .BR auparse_next_record (3). .SH AUTHOR John Dennis audit-userspace-4.0.5/docs/auparse_get_line_number.3000066400000000000000000000014261501761310600225130ustar00rootroot00000000000000.TH "AUPARSE_GET_LINE_NUMBER" "3" "June 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_get_line_number \- get line number where record was found .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_line_number(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_line_number will return the source input line number for the current record of the current event. Line numbers start at 1. If the source input type is AUSOURCE_FILE_ARRAY the line numbering will reset back to 1 each time a new line in the file array is opened. .SH "RETURN VALUE" Returns the line number. Line numbers are 1 based, a zero value indicates the line number information is unavailable. .SH "SEE ALSO" .BR auparse_get_filename (3). .BR auparse_next_record (3). .SH AUTHOR John Dennis audit-userspace-4.0.5/docs/auparse_get_milli.3000066400000000000000000000010671501761310600213230ustar00rootroot00000000000000.TH "AUPARSE_GET_MILLI" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_milli \- get the millisecond value of the event .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_milli(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_milli gets the millisecond value of the current event. .SH "RETURN VALUE" Returns 0 if an error occurs; otherwise, the value of the millisecond portion of the timestamp. .SH "SEE ALSO" .BR auparse_get_timestamp (3), .BR auparse_get_time (3). .BR auparse_get_node (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_node.3000066400000000000000000000013501501761310600211350ustar00rootroot00000000000000.TH "AUPARSE_GET_NODE" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_node \- get the event's machine node name .SH "SYNOPSIS" .B #include .sp const char *auparse_get_node(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_node gets the machine's node name if it exists in the audit event from the current event's timestamp data structure. Not all records have node names since its an admin configurable option. .SH "RETURN VALUE" Returns a copy of the node name or NULL if it does not exist or there was an error. The caller must free the string. .SH "SEE ALSO" .BR auparse_get_timestamp (3), .BR auparse_get_time (3), .BR auparse_get_milli (3). .BR auparse_get_serial (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_num_fields.3000066400000000000000000000007721501761310600223440ustar00rootroot00000000000000.TH "AUPARSE_GET_NUM_FIELDS" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_num_fields \- get the number of fields .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_num_fields(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_num_fields gets the number of fields in the current record of the current event. .SH "RETURN VALUE" Returns 0 if an error occurs; otherwise, the number of fields. .SH "SEE ALSO" .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_num_records.3000066400000000000000000000007531501761310600225360ustar00rootroot00000000000000.TH "AUPARSE_GET_NUM_RECORDS" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_num_records \- get the number of records .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_num_records(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_num_records gets the number of records in the current event. .SH "RETURN VALUE" Returns 0 if an error occurs; otherwise, the number of records. .SH "SEE ALSO" .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_record_num.3000066400000000000000000000013211501761310600223430ustar00rootroot00000000000000.TH "AUPARSE_GET_RECORD_NUM" "3" "Dec 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_get_record_num \- get current record cursor location .SH "SYNOPSIS" .B #include .sp unsigned int auparse_get_record_num(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_record_num will retrieve the internal library cursors current record location in the current event. Records within the same event are numbered starting from 0. This is generally not needed but there are some cases where one may want to know the exact record being looked at. .SH "RETURN VALUE" Returns the current record cursor location. .SH "SEE ALSO" .BR auparse_goto_record_num (3), auparse_get_field_num (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_record_text.3000066400000000000000000000007601501761310600225360ustar00rootroot00000000000000.TH "AUPARSE_GET_RECORD_TEXT" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_record_text \- access unparsed record data .SH "SYNOPSIS" .B #include .sp const char *auparse_get_record_text(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_record_text returns a pointer to the full unparsed record. .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, a pointer to the record. .SH "SEE ALSO" .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_serial.3000066400000000000000000000011321501761310600214650ustar00rootroot00000000000000.TH "AUPARSE_GET_SERIAL" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_serial \- get the event's serial number .SH "SYNOPSIS" .B #include .sp unsigned long auparse_get_serial(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_serial gets the serial number value from the current event's timestamp data structure. .SH "RETURN VALUE" Returns 0 if an error occurs; otherwise, the serial number for the event. .SH "SEE ALSO" .BR auparse_get_timestamp (3), .BR auparse_get_time (3), .BR auparse_get_milli (3). .BR auparse_get_node (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_time.3000066400000000000000000000011341501761310600211460ustar00rootroot00000000000000.TH "AUPARSE_GET_TIME" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_time \- get event's time .SH "SYNOPSIS" .B #include .sp time_t auparse_get_time(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_time will access just the time portion of the timestamp data structure for the current event. .SH "RETURN VALUE" Returns 0 if an error occurs; otherwise, the valid time value in time_t format. .SH "SEE ALSO" .BR time (3), .BR auparse_get_timestamp (3), .BR auparse_get_milli (3). .BR auparse_get_serial (3). .BR auparse_get_node (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_timestamp.3000066400000000000000000000016601501761310600222170ustar00rootroot00000000000000.TH "AUPARSE_GET_TIMESTAMP" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_get_timestamp \- access timestamp of the event .SH "SYNOPSIS" .B #include .sp const au_event_t *auparse_get_timestamp(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_timestamp provides an accessor function for the event's timestamp data structure. The data structure is as follows: .nf typedef struct { time_t sec; // Event seconds unsigned int milli; // millisecond of the timestamp unsigned long serial; // Serial number of the event const char *host; // Machine's node name } au_event_t; .fi .SH "RETURN VALUE" Returns NULL if an error occurs; otherwise, a valid pointer to the data. .SH "SEE ALSO" .BR auparse_get_time (3), .BR auparse_get_milli (3), .BR auparse_get_serial (3), .BR auparse_get_node (3), .BR auparse_timestamp_compare (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_type.3000066400000000000000000000010001501761310600211610ustar00rootroot00000000000000.TH "AUPARSE_GET_TYPE" "3" "Mar 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_get_type \- get record's type .SH "SYNOPSIS" .B #include .sp int auparse_get_type(const auparse_state_t *au); .SH "DESCRIPTION" auparse_get_type will return the integer value for the current record of the current event. .SH "RETURN VALUE" auparse_get_type returns 0 if an error occurs; otherwise, the record's type. .SH "SEE ALSO" .BR auparse_get_type_name (3), auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_get_type_name.3000066400000000000000000000010771501761310600221770ustar00rootroot00000000000000.TH "AUPARSE_GET_TYPE_NAME" "3" "Mar 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_get_type_name \- get record's type translation .SH "SYNOPSIS" .B #include .sp const char *auparse_get_type_name(const auparse_state_t *au); .SH "DESCRIPTION" The auparse_get_type_name function will return the text representation of the name of the current record type. .SH "RETURN VALUE" The auparse_get_type_name function returns NULL on error; otherwise a pointer to a string. .SH "SEE ALSO" .BR auparse_get_type (3), auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_goto_field_num.3000066400000000000000000000013521501761310600223450ustar00rootroot00000000000000.TH "AUPARSE_GOTO_FIELD_NUM" "3" "Dec 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_goto_field_num \- move field cursor to specific field .SH "SYNOPSIS" .B #include .sp int auparse_goto_field_num(const auparse_state_t *au, unsigned int num); .SH "DESCRIPTION" auparse_goto_field_num will move the internal library cursors to point to a specific field number in the current record. Fields within the same record are numbered starting from 0. This is generally not needed but there are some cases where one may want precise control over the exact field being looked at. .SH "RETURN VALUE" Returns 0 on error or 1 for success. .SH "SEE ALSO" .BR auparse_get_field_num (3), auparse_goto_record_num (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_goto_record_num.3000066400000000000000000000013431501761310600225400ustar00rootroot00000000000000.TH "AUPARSE_GOTO_RECORD_NUM" "3" "May 2008" "Red Hat" "Linux Audit API" .SH NAME auparse_goto_record_num \- move record cursor to specific record .SH "SYNOPSIS" .B #include .sp int auparse_goto_record_num(const auparse_state_t *au, unsigned int num); .SH "DESCRIPTION" auparse_goto_record_num will move the internal library cursors to point to a specific physical record number. Records within the same event are numbered starting from 0. This is generally not needed but there are some cases where one may want precise control over the exact record being looked at. .SH "RETURN VALUE" Returns 0 on error or 1 for success. .SH "SEE ALSO" .BR auparse_get_num_records (3), auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_init.3000066400000000000000000000032121501761310600203130ustar00rootroot00000000000000.TH "AUPARSE_INIT" "3" "Jan 2023" "Red Hat" "Linux Audit API" .SH NAME auparse_init \- initialize an instance of the audit parsing library .SH "SYNOPSIS" .B #include .sp auparse_state_t *auparse_init(ausource_t source, const void *b); .SH "DESCRIPTION" auparse_init initializes an instance of the audit parsing library. The function returns an opaque pointer to the parser's internal state. It is used in subsequent calls to the library so. The source variable determines where the library looks for data. Legal values can be: .nf AUSOURCE_LOGS - use audit logs AUSOURCE_FILE - use a file AUSOURCE_FILE_ARRAY - use several files AUSOURCE_BUFFER - use a buffer AUSOURCE_BUFFER_ARRAY - use an array of buffers AUSOURCE_DESCRIPTOR - use a particular descriptor AUSOURCE_FILE_POINTER - use a stdio FILE pointer AUSOURCE_FEED - feed data to parser with auparse_feed() .fi The pointer 'b' is used to set the file name, array of filenames, the buffer address, or an array of pointers to buffers, or the descriptor number based on what source is given. When the data source is an array of files or buffers, you would create an array of pointers with the last one being a NULL pointer. Buffers should be NUL terminated. The data structure returned by auparse_init is not thread-safe. If you need to use it in a multithreaded program, you will need to add locking around any use of the data structure. .SH "RETURN VALUE" Returns a NULL pointer if an error occurs; otherwise, the return value is an opaque pointer to the parser's internal state. .SH "SEE ALSO" .BR auparse_reset (3), .BR auparse_destroy (3). .BR auparse_feed (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_interpret_field.3000066400000000000000000000045051501761310600225350ustar00rootroot00000000000000.TH "AUPARSE_INTERPRET_FIELD" "3" "August 2017" "Red Hat" "Linux Audit API" .SH NAME .nf auparse_interpret_field, auparse_interpret_realpath,auparse_interpret_sock_family,auparse_interpret_sock_port,auparse_interpret_sock_address \- get current field's interpreted value .fi .SH "SYNOPSIS" .nf .B #include .sp const char *auparse_interpret_field(const auparse_state_t *au); const char *auparse_interpret_realpath(const auparse_state_t *au); const char *auparse_interpret_sock_family(auparse_state_t *au); const char *auparse_interpret_sock_port(auparse_state_t *au); const char *auparse_interpret_sock_address(auparse_state_t *au); .SH "DESCRIPTION" .B auparse_interpret_field allows access to the interpreted value in the current field of the current record in the current event. The returned string is escaped using the chosen method. The returned value will be destroyed if you call this function again. If you need to interpret another field and keep this value, you will have to copy it for later use. Examples of things that could be interpreted are: uid, gid, syscall numbers, exit codes, file paths, socket addresses, permissions, modes, and capabilities. There are likely to be more in the future. If a value cannot be interpreted, its original value is returned. .B auparse_interpret_realpath is like auparse_interpret_field except that it will call realpath on the results of gluing the cwd and file together. This also implies that it only valid to be called for the file name given in a PATH record. .B auparse_interpret_sock_family will only return the socket family portion of a socket address. .B auparse_interpret_sock_port will only return the port portion of a socket address. Not all socket families have a port. If that is the case, you will get a NULL value in which case your best option is to use the normal interpretation function. .B auparse_interpret_sock_address will only return the address portion of a socket address. Not all socket families have an ip address. If that is the case, you will get a NULL value in which case your best option is to use the normal interpretation function. .SH "RETURN VALUE" Returns NULL if there is an error otherwise a pointer to the interpreted value. .SH "SEE ALSO" .BR auparse_get_field_int (3), .BR auparse_get_field_str (3), .BR auparse_set_escape_mode (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_metrics.3000066400000000000000000000013661501761310600210260ustar00rootroot00000000000000.TH "AUPARSE_METRICS" "3" "Sept 2023" "Red Hat" "Linux Audit API" .SH NAME auparse_metrics \- get some metrics about auparse .SH "SYNOPSIS" .B #include .sp char *auparse_metrics(const auparse_state_t *au); .SH "DESCRIPTION" auparse_metrics gets some basic information about auparse's internal state. It returns a character string ready to print. It returns the current limit for storing building events, the maximum events building or ready, and the number of ready events for processing. This information is only useful when the feed api is being used. .SH "RETURN VALUE" Returns a memory buffer of current metrics on success and NULL on error. The caller must free the string. .SH "SEE ALSO" .BR auparse_feed (3) .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_new_buffer.3000066400000000000000000000014321501761310600214740ustar00rootroot00000000000000.TH "AUPARSE_NEW_BUFFER" "3" "Feb 2021" "Red Hat" "Linux Audit API" .SH NAME auparse_new_buffer \- replace the buffer in the parser .SH "SYNOPSIS" .B #include .sp .nf int auparse_new_buffer(auparse_state_t *au, const char *data, size_t data_len); .fi .TP .I au The audit parse state .TP .I data a buffer of data to give to the parser, it is .I data_len bytes long. The data is copied in the parser, upon return the caller may free or reuse the data buffer. .TP .I data_len number of bytes in .I data .SH "DESCRIPTION" .I auparse_new_buffer replaces the data that the parser works on. .I auparse_init() must have been called with a source type of AUSOURCE_BUFFER. .SH "RETURN VALUE" Returns 1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR auparse_init (3) audit-userspace-4.0.5/docs/auparse_next_event.3000066400000000000000000000011061501761310600215270ustar00rootroot00000000000000.TH "AUPARSE_NEXT_EVENT" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_next_event \- get the next event .SH "SYNOPSIS" .B #include .sp int auparse_next_event(auparse_state_t *au); .SH "DESCRIPTION" auparse_next_event will position the cursors at the first field of the first record of the next event in a file or buffer. It does not skip events or honor any search criteria that may be stored. .SH "RETURN VALUE" Returns \-1 if an error occurs, 0 if there's no data, 1 for success. .SH "SEE ALSO" .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_next_field.3000066400000000000000000000007651501761310600215030ustar00rootroot00000000000000.TH "AUPARSE_NEXT_FIELD" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_next_field \- move field cursor .SH "SYNOPSIS" .B #include .sp int auparse_next_field(const auparse_state_t *au); .SH "DESCRIPTION" auparse_next_field moves the library's internal cursor to point to the next field in the current record of the current event. .SH "RETURN VALUE" Returns 0 if no more fields exist and 1 for success. .SH "SEE ALSO" .BR auparse_next_record (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_next_record.3000066400000000000000000000014461501761310600216730ustar00rootroot00000000000000.TH "AUPARSE_NEXT_RECORD" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_next_record \- move record cursor .SH "SYNOPSIS" .B #include .sp int auparse_next_record(auparse_state_t *au); .SH "DESCRIPTION" auparse_next_record will move the internal library cursors to point to the next record of the current event. You should not call this function from a feed interface callback function. Doing so will deadlock the code. In that scenario, you should check the number of records in the current event with auparse_get_num_records and only call this if there are more records. .SH "RETURN VALUE" Returns \-1 if an error occurs, 0 if no more records in current event, or 1 for success. .SH "SEE ALSO" .BR auparse_next_event (3), auparse_get_num_records (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_node_compare.3000066400000000000000000000011441501761310600220050ustar00rootroot00000000000000.TH "AUPARSE_NODE_COMPARE" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_node_compare \- compares node name values .SH "SYNOPSIS" .B #include .sp int auparse_node_compare(const au_event_t *e1, const au_event_t *e2); .SH "DESCRIPTION" auparse_node_compare compares the node name values of 2 events. .SH "RETURN VALUE" Returns \-1, 0, or 1 respectively depending on whether e2 is less than, equal to, or greater than e1. Since this is a string compare, it probably only matter that they are equal or not equal. .SH "SEE ALSO" .BR auparse_get_timestamp (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_normalize.3000066400000000000000000000016451501761310600213600ustar00rootroot00000000000000.TH "AUPARSE_NORMALIZE" "3" "Feb 2017" "Red Hat" "Linux Audit API" .SH NAME auparse_normalize \- normalize the current event .SH "SYNOPSIS" .B #include .sp .B int auparse_normalize(auparse_state_t *au, normalize_option_t opt); .SH "DESCRIPTION" .B auparse_normalize analyzes the current event so that the important information about the event can be accessed through a normalized API which positions to internal field cursor to the exact record and field when asked about specific information. The auparse_normalize function takes an opt argument to tell it how much information to gather. Legal values are: .nf NORM_OPT_ALL - gather maximum information NORM_OPT_NO_ATTRS - do not gather subject/object attribute information .fi .SH "RETURN VALUE" Returns 0 on success and 1 on error. .SH "SEE ALSO" .BR auparse_normalize_subject_primary (3) , .BR auparse_normalize_object_primary (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_normalize_functions.3000066400000000000000000000055071501761310600234510ustar00rootroot00000000000000.TH "AUPARSE_NORMALIZE_FUNCTIONS" "3" "March 2017" "Red Hat" "Linux Audit API" .SH NAME .nf auparse_normalize_get_event_kind, auparse_normalize_subject_kind, auparse_normalize_get_action, auparse_normalize_object_kind, auparse_normalize_how, auparse_normalize_session, auparse_normalize_subject_primary, auparse_normalize_subject_secondary, auparse_normalize_subject_first_attribute, auparse_normalize_subject_next_attribute, auparse_normalize_object_primary, auparse_normalize_object_secondary, auparse_normalize_object_primary2, auparse_normalize_object_first_attribute, auparse_normalize_object_next_attribute, auparse_normalize_get_results, auparse_normalize_key \- Access normalized fields .fi .SH "SYNOPSIS" .nf .B #include .sp Metadata Functions: .B const char *auparse_normalize_get_event_kind(const auparse_state_t *au); .B const char *auparse_normalize_subject_kind(const auparse_state_t *au); .B const char *auparse_normalize_get_action(const auparse_state_t *au); .B const char *auparse_normalize_object_kind(const auparse_state_t *au); .B const char *auparse_normalize_how(const auparse_state_t *au); .sp Positioning Functions: .B int auparse_normalize_session(auparse_state_t *au); .B int auparse_normalize_subject_primary(auparse_state_t *au); .B int auparse_normalize_subject_secondary(auparse_state_t *au); .B int auparse_normalize_subject_first_attribute(auparse_state_t *au); .B int auparse_normalize_subject_next_attribute(auparse_state_t *au); .B int auparse_normalize_object_primary(auparse_state_t *au); .B int auparse_normalize_object_secondary(auparse_state_t *au); .B int auparse_normalize_object_primary2(auparse_state_t *au); .B int auparse_normalize_object_first_attribute(auparse_state_t *au); .B int auparse_normalize_object_next_attribute(auparse_state_t *au); .B int auparse_normalize_get_results(auparse_state_t *au); .B int auparse_normalize_key(auparse_state_t *au); .fi .SH "DESCRIPTION" After calling the .B auparse_normalize function, you will probably want to access the audit event data. These function provide access to the results of the normalization. There are 2 kinds of function, metadata and positioning. The metadata functions all return a pointer to a string that describes something about the event. This data does not live inside the event but is kept in lookup tables inside the auparse library. The positioning function are different in that they move the internal cursor of auparse to the record and field that contains the information you want. You then use field accessor functions to retrieve the values. .SH "RETURN VALUE" The positioning functions return < 0 on error, 0 if uninitialized, and 1 on success. The metadata functions return NULL on error and a pointer to a string on success. .SH "SEE ALSO" auparse_normalize(3), auparse_get_field_str(3), auparse_interpret_field(3). .BR .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_reset.3000066400000000000000000000007701501761310600205000ustar00rootroot00000000000000.TH "AUPARSE_RESET" "3" "Sep 2014" "Red Hat" "Linux Audit API" .SH NAME auparse_reset \- reset audit parser instance .SH "SYNOPSIS" .B #include .sp int auparse_reset(auparse_state_t *au); .SH "DESCRIPTION" auparse_reset resets all internal cursors to the beginning. It closes files, descriptors, and frees memory buffers. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR auparse_init (3), .BR auparse_destroy (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_set_eoe_timeout.3000066400000000000000000000014511501761310600225440ustar00rootroot00000000000000.TH "AUPARSE_SET_EOE_TIMEOUT" "3" "January 2021" "Red Hat" "Linux Audit API" .SH NAME auparse_set_eoe_timeout \- set the end of event timeout value .SH "SYNOPSIS" .B #include .sp int auparse_set_eoe_timeout(time_t new_tmo) .SH "DESCRIPTION" auparse_set_eoe_timeout is used to set the end of event timeout value (seconds). The value should be a positive integer. If this function is called, it overrides any setting in /etc/auditd.conf. The function should be called after the \fIauparse_init()\fP function call. For details on the timeout, see the \fBend_of_event_timeout\fP configuration item description in \fIauditd.conf(5)\fP. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR auparse_init (3). .BR auditd.conf (8). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_set_escape_mode.3000066400000000000000000000026771501761310600225050ustar00rootroot00000000000000.TH "AUPARSE_SET_ESCAPE_MODE" "3" "July 2016" "Red Hat" "Linux Audit API" .SH NAME auparse_set_escape_mode \- choose escape method .SH "SYNOPSIS" .B #include .sp void auparse_set_escape_mode(auparse_state_t *au, auparse_esc_t mode); .SH "DESCRIPTION" auparse_set_escape_mode is used to set the escaping method that will be used to output interpreted text. The choices for the mode variable are: .RS .TP .B AUPARSE_ESC_RAW No escaping of any kind is done. .TP .B AUPARSE_ESC_TTY Escape TTY control characters so that they are harmless to display on a terminal. When any control character is found, they are displayed as octal numbers. This is the default mode that the auparse library is initialized with. .TP .B AUPARSE_ESC_SHELL Besides escaping control characters, this will escape some characters that can cause problems when used with shell scripting. Any escaped control characters are displayed as octal numbers. Other escaped characters are proceeded with a backslash. The additional characters it escapes are: " ' ` $ \\ .TP .B AUPARSE_ESC_SHELL_QUOTE Similar to .I AUPARSE_ESC_SHELL but expands the character set to include shell operators. Any escaped control characters are displayed as octal numbers. Other escaped characters are proceeded with a backslash. The additional characters it escapes include: ; ' \ " ` # $ & * ? [ ] < > { } \\ .RE .SH "RETURN VALUE" None .SH "SEE ALSO" .BR auparse_interpret_field (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/auparse_timestamp_compare.3000066400000000000000000000010271501761310600230630ustar00rootroot00000000000000.TH "AUPARSE_TIMESTAMP_COMPARE" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME auparse_timestamp_compare \- compares timestamp values .SH "SYNOPSIS" .B #include .sp int auparse_timestamp_compare(const au_event_t *e1, const au_event_t *e2); .SH "DESCRIPTION" auparse_timestamp_compare compares the values of 2 timestamps. .SH "RETURN VALUE" Returns \-1, 0, or 1 respectively depending on whether e2 is less than, equal to, or greater than e1. .SH "SEE ALSO" .BR auparse_get_timestamp (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/aureport.8000066400000000000000000000165741501761310600175150ustar00rootroot00000000000000.TH AUREPORT "8" "February 2023" "Red Hat" "System Administration Utilities" .SH NAME aureport \- a tool that produces summary reports of audit daemon logs .SH SYNOPSIS .B aureport .RI [ options ] .SH DESCRIPTION \fBaureport\fP is a tool that produces summary reports of the audit system logs. The aureport utility can also take input from stdin as long as the input is the raw log data. The reports have a column label at the top to help with interpretation of the various fields. Except for the main summary report, all reports have the audit event number. You can subsequently lookup the full event with ausearch \fB\-a\fP \fIevent number\fP. You may need to specify start & stop times if you get multiple hits. The reports produced by aureport can be used as building blocks for more complicated analysis. .SH OPTIONS .TP .BR \-au ,\ \-\-auth Report about authentication attempts .TP .BR \-a ,\ \-\-avc Report about avc messages .TP .BR \-\-comm Report about commands run .TP .BR \-c ,\ \-\-config Report about config changes .TP .BR \-cr ,\ \-\-crypto Report about crypto events .TP .BR \-\-debug Write malformed events that are skipped to stderr. .TP .BR \-\-eoe\-timeout \ \fIseconds\fP Set the end of event parsing timeout. See \fBend_of_event_timeout\fP in \fIauditd.conf(5)\fP for details. Note that setting this value will override any configured value found in /etc/auditd/auditd.conf. .TP .BR \-e ,\ \-\-event Report about events .TP .BR \-\-escape \ \fIoption\fP This option determines if the output is escaped to make the content safer for certain uses. The options are \fIraw\fP , \fItty\fP , \fIshell\fP , and \fIshell_quote\fP. Each mode includes the characters of the preceding mode and escapes more characters. That is to say \fIshell\fP includes all characters escaped by \fItty\fP and adds more. \fItty\fP is the default. .TP .BR \-f ,\ \-\-file Report about files and af_unix sockets .TP .B \-\-failed Only select failed events for processing in the reports. The default is both success and failed events. .TP .BR \-h ,\ \-\-host Report about hosts .TP .BR \-\-help Print brief command summary .TP .BR \-i ,\ \-\-interpret Interpret numeric entities into text. For example, uid is converted to account name. The conversion is done using the current resources of the machine where the search is being run. If you have renamed the accounts, or don't have the same accounts on your machine, you could get misleading results. .TP .BR \-if ,\ \-\-input \ \fIfile\fP\ |\ \fIdirectory\fP Use the given \fIfile\fP or \fIdirectory\fP instead of the logs. This is to aid analysis where the logs have been moved to another machine or only part of a log was saved. The path length is limited to 4064 bytes. .TP .B \-\-input\-logs Use the log file location from auditd.conf as input for analysis. This is needed if you are using aureport from a cron job. .TP .BR \-\-integrity Report about integrity events .TP .BR \-k ,\ \-\-key Report about audit rule keys .TP .BR \-l ,\ \-\-login Report about logins .TP .BR \-m ,\ \-\-mods Report about account modifications .TP .BR \-ma ,\ \-\-mac Report about Mandatory Access Control (MAC) events .TP .BR \-n ,\ \-\-anomaly Report about anomaly events. These events include NIC going into promiscuous mode and programs segfaulting. .TP .BR \-\-node \ \fInode-name\fP Only select events originating from \fInode name\fP string for processing in the reports. The default is to include all nodes. Multiple nodes are allowed. .TP .BR \-nc ,\ \-\-no-config Do not include the CONFIG_CHANGE event. This is particularly useful for the key report because audit rules have key labels in many cases. Using this option gets rid of these false positives. .TP .BR \-p ,\ \-\-pid Report about processes .TP .BR \-r ,\ \-\-response Report about responses to anomaly events .TP .BR \-s ,\ \-\-syscall Report about syscalls .TP .B \-\-success Only select successful events for processing in the reports. The default is both success and failed events. .TP .B \-\-summary Run the summary report that gives a total of the elements of the main report. Not all reports have a summary. .TP .BR \-t ,\ \-\-log This option will output a report of the start and end times for each log. .TP .BR \-\-tty Report about tty keystrokes .TP .BR \-te ,\ \-\-end \ [\fIend-date\fP]\ [\fIend-time\fP] Search for events with time stamps equal to or before the given end time. The format of end time depends on your locale. If the date is omitted, .B today is assumed. If the time is omitted, .B now is assumed. Use 24 hour clock time rather than AM or PM to specify time. An example date using the en_US.utf8 locale is 09/03/2009. An example of time is 18:00:00. The date format accepted is influenced by the LC_TIME environmental variable. You may also use the word: \fBnow\fP, \fBrecent\fP, \fBthis-hour\fP, \fBboot\fP, \fBtoday\fP, \fByesterday\fP, \fBthis\-week\fP, \fBweek\-ago\fP, \fBthis\-month\fP, \fBthis\-year\fP. \fBNow\fP means starting now. \fBRecent\fP is 10 minutes ago. \fBBoot\fP means the time of day to the second when the system last booted. \fBToday\fP means now. \fBYesterday\fP is 1 second after midnight the previous day. \fBThis\-week\fP means starting 1 second after midnight on day 0 of the week determined by your locale (see \fBlocaltime\fP). \fBWeek\-ago\fP means 1 second after midnight exactly 7 days ago. \fBThis\-month\fP means 1 second after midnight on day 1 of the month. \fBThis\-year\fP means the 1 second after midnight on the first day of the first month. .TP .BR \-tm ,\ \-\-terminal Report about terminals .TP .BR \-ts ,\ \-\-start \ [\fIstart-date\fP]\ [\fIstart-time\fP] Search for events with time stamps equal to or after the given end time. The format of end time depends on your locale. If the date is omitted, .B today is assumed. If the time is omitted, .B midnight is assumed. Use 24 hour clock time rather than AM or PM to specify time. An example date using the en_US.utf8 locale is 09/03/2009. An example of time is 18:00:00. The date format accepted is influenced by the LC_TIME environmental variable. You may also use the word: \fBnow\fP, \fBrecent\fP, \fBthis-hour\fP, \fBboot\fP, \fBtoday\fP, \fByesterday\fP, \fBthis\-week\fP, \fBweek\-ago\fP, \fBthis\-month\fP, \fBthis\-year\fP. \fBBoot\fP means the time of day to the second when the system last booted. \fBToday\fP means starting at 1 second after midnight. \fBRecent\fP is 10 minutes ago. \fBYesterday\fP is 1 second after midnight the previous day. \fBThis\-week\fP means starting 1 second after midnight on day 0 of the week determined by your locale (see \fBlocaltime\fP). \fBWeek\-ago\fP means starting 1 second after midnight exactly 7 days ago. \fBThis\-month\fP means 1 second after midnight on day 1 of the month. \fBThis\-year\fP means the 1 second after midnight on the first day of the first month. .TP .BR \-u ,\ \-\-user Report about users .TP .BR \-v ,\ \-\-version Print the version and exit .TP .BR \-\-virt Report about Virtualization events .TP .BR \-x ,\ \-\-executable Report about executables .SH NOTE The boot time option is a convenience function and has limitations. The time it calculates is based on time now minus /proc/uptime. If after boot the system clock has been adjusted, perhaps by ntp, then the calculation may be wrong. In that case you'll need to fully specify the time. You can check the time it would use by running: date -d "`cut \-f1 \-d. /proc/uptime` seconds ago" .SH "SEE ALSO" .BR ausearch (8), .BR auditd (8), .BR auditd.conf (5). audit-userspace-4.0.5/docs/ausearch-expression.5000066400000000000000000000130661501761310600216320ustar00rootroot00000000000000.TH "AUSEARCH-EXPRESSION" "5" "Feb 2008" "Red Hat" "Linux Audit" .SH NAME ausearch-expression \- audit search expression format .SH OVERVIEW This man page describes the format of "ausearch expressions". Parsing and evaluation of these expressions is provided by libauparse and is common to applications that use this library. .SH LEXICAL STRUCTURE White space (ASCII space, tab and new-line characters) between tokens is ignored. The following tokens are recognized: .TP Punctuation .B ( ) \e .TP Logical operators .B ! && || .TP Comparison operators .B < <= == > >= !== i= i!= r= r!= .TP Unquoted strings Any non-empty sequence of ASCII letters, digits, and the .B _ symbol. .TP Quoted strings A sequence of characters surrounded by the .B \(dq quotes. The .B \e character starts an escape sequence. The only defined escape sequences are .B \e\e and \fB\e\(dq\fR. The semantics of other escape sequences is undefined. .TP Regexps A sequence of characters surrounded by the .B / characters. The .B \e character starts an escape sequence. The only defined escape sequences are .B \e\e and \fB\e/\fR. The semantics of other escape sequences is undefined. .PP Anywhere an unquoted string is valid, a quoted string is valid as well, and vice versa. In particular, field names may be specified using quoted strings, and field values may be specified using unquoted strings. .SH EXPRESSION SYNTAX The primary expression has one of the following forms: .IP .I field comparison-operator value .B \eregexp .I string-or-regexp .PP .I field is either a string, which specifies the first field with that name within the current audit record, or the .B \e escape character followed by a string, which specifies a virtual field with the specified name (virtual fields are defined in a later section). .I field is a string. .I operator specifies the comparison to perform .TP .B r= r!= Get the "raw" string of \fIfield\fR, and compare it to \fIvalue\fR. For fields in audit records, the "raw" string is the exact string stored in the audit record (with all escaping and unprintable character encoding left alone); applications can read the "raw" string using .BR auparse_get_field_str (3). Each virtual field may define a "raw" string. If .I field is not present or does not define a "raw" string, the result of the comparison is .B false (regardless of the operator). .TP .B i= i!= Get the "interpreted" string of \fIfield\fR, and compare it to \fIvalue\fR. For fields in audit records, the "interpreted" string is an "user-readable" interpretation of the field value; applications can read the "interpreted" string using .BR auparse_interpret_field (3). Each virtual field may define an "interpreted" string. If .I field is not present or does not define an "interpreted" string, the result of the comparison is .B false (regardless of the operator). .TP .B < <= == > >= !== Evaluate the "value" of \fIfield\fR, and compare it to \fIvalue\fR. A "value" may be defined for any field or virtual field, but no "value" is currently defined for any audit record field. The rules of parsing \fIvalue\fR for comparing it with the "value" of .I field are specific for each \fIfield\fR. If .I field is not present, the result of the comparison is .B false (regardless of the operator). If .I field does not define a "value", an error is reported when parsing the expression. .PP In the special case of .B \eregexp \fIregexp-or-string\fR, the current audit record is taken as a string (without interpreting field values), and matched against \fIregexp-or-string\fR. .I regexp-or-string is an extended regular expression, using a string or regexp token (in other words, delimited by .B \(dq or \fB/\fR). If .I E1 and .I E2 are valid expressions, then .B ! \fIE1\fR, .I E1 .B && \fIE2\fR, and .I E1 .B || .I E2 are valid expressions as well, with the usual C semantics and evaluation priorities. Note that .B ! .I field op value is interpreted as \fB!(\fIfield op value\fB)\fR, not as \fB(!\fIfield\fB)\fI op value\fR. .SH VIRTUAL FIELDS The following virtual fields are defined: .TP .B \etimestamp The value is the timestamp of the current event. .I value must be formatted as: .sp .in +5 .nf .na ts:seconds.milli .ad .fi .in -5 .sp where .I seconds and .I milli are decimal numbers specifying the seconds and milliseconds part of the timestamp, respectively. .TP .B \etimestamp_ex This is similar to .B \etimestamp but also includes the event's serial number. .I value must be formatted as: .sp .in +5 .nf .na ts:seconds.milli:serial .ad .fi .in -5 .sp where .I serial is a decimal number specifying the event's serial number. .TP .B \erecord_type The value is the type of the current record. .I value is either the record type name, or a decimal number specifying the type. .SH SEMANTICS The expression as a whole applies to a single record. The expression is .B true for a specified event if it is .B true for any record associated with the event. .SH EXAMPLES As a demonstration of the semantics of handling missing fields, the following expression is .B true if .I field is present: .IP .B (\fIfield\fB r= \(dq\(dq) || (\fIfield\fB r!= \(dq\(dq) .PP and the same expression surrounded by .B !( and .B ) is .B true if .I field is not present. .SH FUTURE DIRECTIONS New escape sequences for quoted strings may be defined. For currently defined virtual fields that do not define a "raw" or "interpreted" string, the definition may be added. Therefore, don't rely on the fact that comparing the "raw" or "interpreted" string of the field with any value is \fBfalse\fR. New formats of value constants for the .B \etimestamp virtual field may be added. .SH AUTHOR Miloslav Trmac audit-userspace-4.0.5/docs/ausearch.8000066400000000000000000000411621501761310600174360ustar00rootroot00000000000000.TH AUSEARCH "8" "July 2023" "Red Hat" "System Administration Utilities" .SH NAME ausearch \- a tool to query audit daemon logs .SH SYNOPSIS .B ausearch .RI [ options ] .SH DESCRIPTION \fBausearch\fP is a tool that can query the audit daemon logs based for events based on different search criteria. The ausearch utility can also take input from stdin as long as the input is the raw log data. Each commandline option given forms an "and" statement. For example, searching with \fB\-m\fP and \fB\-ui\fP means return events that have both the requested type and match the user id given. An exception is the \fB\-m\fP and \fB\-n\fP options; multiple record types and nodes are allowed in a search which will return any matching node and record. It should also be noted that each syscall excursion from user space into the kernel and back into user space has one event ID that is unique. Any auditable event that is triggered during this trip share this ID so that they may be correlated. Different parts of the kernel may add supplemental records. For example, an audit event on the syscall "open" will also cause the kernel to emit a PATH record with the file name. The ausearch utility will present all records that make up one event together. This could mean that even though you search for a specific kind of record, the resulting events may contain SYSCALL records. Also be aware that not all record types have the requested information. For example, a PATH record does not have a hostname or a loginuid. .SH OPTIONS .TP .BR \-a ,\ \-\-event \ \fIaudit-event-id\fP Search for an event based on the given \fIevent ID\fP. Messages always start with something like msg=audit(1116360555.329:2401771). The event ID is the number after the ':'. All audit events that are recorded from one application's syscall have the same audit event ID. A second syscall made by the same application will have a different event ID. This way they are unique. .TP .BR \-\-arch \ \fICPU\fP Search for events based on a specific CPU architecture. If you do not know the arch of your machine but you want to use the 32 bit syscall table and your machine supports 32 bits, you can also use .B b32 for the arch. The same applies to the 64 bit syscall table, you can use .B b64. The arch of your machine can be found by doing 'uname -m'. .TP .BR \-c ,\ \-\-comm \ \fIcomm-name\fP Search for an event based on the given \fIcomm name\fP. The comm name is the executable's name from the task structure. .TP .BR \-\-debug Write malformed events that are skipped to stderr. .TP .BR \-\-checkpoint \ \fIcheckpoint-file\fP Checkpoint the output between successive invocations of ausearch such that only events not previously output will print in subsequent invocations. An auditd event is made up of one or more records. When processing events, ausearch defines events as either complete or in-complete. A complete event is either a single record event or one whose event time occurred 2 seconds in the past compared to the event being currently processed. A checkpoint is achieved by recording the last completed event output along with the device number and inode of the file the last completed event appeared in \fIcheckpoint-file\fP. On a subsequent invocation, ausearch will load this checkpoint data and as it processes the log files, it will discard all complete events until it matches the checkpointed one. At this point, it will start outputting complete events. Should the file or the last checkpointed event not be found, one of a number of errors will result and ausearch will terminate. See \fBEXIT STATUS\fP for detail. .TP .BR \-\-eoe\-timeout \ \fIseconds\fP Set the end of event parsing timeout. See \fBend_of_event_timeout\fP in \fIauditd.conf(5)\fP for details. Note that setting this value will override any configured value found in /etc/auditd/auditd.conf. .TP .BR \-e,\ \-\-exit \ \fIexit-code-or-errno\fP Search for an event based on the given syscall \fIexit code or errno\fP. .TP .BR \-\-escape \ \fIoption\fP This option determines if the output is escaped to make the content safer for certain uses. The options are \fIraw\fP , \fItty\fP , \fIshell\fP , and \fIshell_quote\fP. Each mode includes the characters of the preceding mode and escapes more characters. That is to say \fIshell\fP includes all characters escaped by \fItty\fP and adds more. \fItty\fP is the default. .TP .BR \-\-extra-keys \ When the \fIformat\fP mode is \fIcsv\fP, this option will add a final column with key information if its exists for the event. This would only occur on SYSCALL records which were the result of triggering an audit rule that defines a key. .TP .BR \-\-extra-labels \ When the \fIformat\fP mode is \fIcsv\fP, this option will add columns of information about subject and object labels when they exist. .TP .BR \-\-extra-obj2 \ When the \fIformat\fP mode is \fIcsv\fP, this option will add columns of information about a second object when it exists. It's rare that a second object is part of a record. Some examples are when a file is renamed from one name to another or when a device is mounted to a path. .TP .BR \-\-extra-time \ When the \fIformat\fP mode is \fIcsv\fP, this option will add columns of information about broken down time to make subsetting easier. .TP .BR \-f ,\ \-\-file \ \fIfile-name\fP Search for an event based on the given \fIfilename\fP. The argument will match normal files as well as af_unix sockets. .TP .BR \-\-format \ \fIoption\fP Events that match the search criteria are formatted using this option. The supported formats are: raw, default, interpret, csv, and text. The \fIraw\fP option is described under the \fI\-\-raw\fP command line option. The \fIdefault\fP option is what you get when no formatting options are passed. It includes one line as a visual separator which indicates the time stamp and then the records of the event follow. The \fIinterpret\fP option is explained under the \fI\-i\fP command line option. The \fIcsv\fP option outputs the results of the search as a normalized event in comma separated value (CSV) format suitable for import into analytical programs. The \fItext\fP option turns the event into an English sentence that is easier to understand than other options, but it comes at the expense of loss of detail. In most cases this is perfectly fine since the original event still retains all the original information. .TP .BR \-ga ,\ \-\-gid\-all \ \fIall-group-id\fP Search for an event with either effective group ID or group ID matching the given \fIgroup ID\fP. .TP .BR \-ge ,\ \-\-gid\-effective \ \fIeffective-group-id\fP Search for an event with the given \fIeffective group ID\fP or group name. .TP .BR \-gi ,\ \-\-gid \ \fIgroup-id\fP Search for an event with the given \fIgroup ID\fP or group name. .TP .BR \-h ,\ \-\-help Help .TP .BR \-hn ,\ \-\-host \ \fIhost-name\fP Search for an event with the given \fIhost name\fP. The hostname can be either a hostname, fully qualified domain name, or numeric network address. No attempt is made to resolve numeric addresses to domain names or aliases. This search typically correlates to the addr or host field of audit events. Also see the \-\-node command which searches the node field. .TP .BR \-i ,\ \-\-interpret Interpret numeric entities into text. For example, uid is converted to account name. If the audit logs are unenriched, the conversion is done using the current resources of the machine where the search is being run. If you have renamed the accounts, or don't have the same accounts on your machine, you could get misleading results. If the logs are enriched, it uses the supplemental data to do the conversion. This allows accurate log reporting even when run on a different machine than the original logs came from. .TP .BR \-if ,\ \-\-input \ \fIfile-name\fP\ |\ \fIdirectory\fP Use the given \fIfile\fP or \fIdirectory\fP instead of the logs. This is to aid analysis where the logs have been moved to another machine or only part of a log was saved. The path length is limited to 4064 bytes. .TP .BR \-\-input\-logs Use the log file location from auditd.conf as input for searching. This is needed if you are using ausearch from a cron job. .TP .BR \-\-just\-one Stop after emitting the first event that matches the search criteria. .TP .BR \-k ,\ \-\-key \ \fIkey-string\fP Search for an event based on the given \fIkey string\fP. .TP .BR \-l ,\ \-\-line\-buffered Flush output on every line. Most useful when stdout is connected to a pipe and the default block buffering strategy is undesirable. May impose a performance penalty. .TP .BR \-m ,\ \-\-message \ \fImessage-type\fP\ |\ \fIcomma-sep-message-type-list\fP Search for an event matching the given \fImessage type\fP. (Message types are also known as record types.) You may also enter a \fIcomma separated list of message types\fP or multiple individual message types each with its own \fI-m\fP option. There is an \fBALL\fP message type that doesn't exist in the actual logs. It allows you to get all messages in the system. The list of valid messages types is long. The program will display the list whenever no message type is passed with this parameter. The message type can be either text or numeric. If you enter a list, there can be only commas and no spaces separating the list. .TP .BR \-n ,\ \-\-node Search for events originating from a specific machine. Multiple nodes are allowed, and if any nodes match, the event is matched. This search uses the node field in audit events. Also see the \-\-host command which search for events related to host information in the audit trail. .TP .BR \-o ,\ \-\-object \ \fISE-Linux-context-string\fP Search for event with \fItcontext\fP (object) matching the string. .TP .BR \-p ,\ \-\-pid \ \fIprocess-id\fP Search for an event matching the given \fIprocess ID\fP. .TP .BR \-pp ,\ \-\-ppid \ \fIparent-process-id\fP Search for an event matching the given \fIparent process ID\fP. .TP .BR \-r ,\ \-\-raw Output is completely unformatted. This is useful for extracting records to a file that can still be interpreted by audit tools or when piping to other audit tools. .TP .BR \-sc ,\ \-\-syscall \ \fIsyscall-name-or-value\fP Search for an event matching the given \fIsyscall\fP. You may either give the numeric syscall value or the syscall name. If you give the syscall name, it will use the syscall table for the machine that you are using. .TP .BR \-se ,\ \-\-context \ \fISE-Linux-context-string\fP Search for events with either \fIscontext\fP/subject or \fItcontext\fP/object matching the given string. .TP .BR \-\-session \ \fILogin-Session-ID\fP Search for events matching the given Login Session ID. This process attribute is set when a user logs in and can tie any process to a particular user login. .TP .BR \-su ,\ \-\-subject \ \fISE-Linux-context-string\fP Search for event with \fIscontext\fP (subject) matching the string. .TP .BR \-sv ,\ \-\-success \ \fIsuccess-value\fP Search for an event matching the given \fIsuccess value\fP. Legal values are .B yes and .BR no . .TP .BR \-te ,\ \-\-end \ [\fIend-date\fP]\ [\fIend-time\fP] Search for events with time stamps equal to or before the given end time. The format of end time depends on your locale. You can check the format of your locale by running .B date \(aq+%x\(aq. If the date is omitted, .B today is assumed. If the time is omitted, .B now is assumed. Use 24 hour clock time rather than AM or PM to specify time. An example date using the en_US.utf8 locale is 09/03/2009. An example of time is 18:00:00. The date format accepted is influenced by the LC_TIME environmental variable. You may also use the word: \fBnow\fP, \fBrecent\fP, \fBthis-hour\fP, \fBboot\fP, \fBtoday\fP, \fByesterday\fP, \fBthis\-week\fP, \fBweek\-ago\fP, \fBthis\-month\fP, or \fBthis\-year\fP. \fBNow\fP means starting now. \fBRecent\fP is 10 minutes ago. \fBBoot\fP means the time of day to the second when the system last booted. \fBToday\fP means now. \fBYesterday\fP is 1 second after midnight the previous day. \fBThis\-week\fP means starting 1 second after midnight on day 0 of the week determined by your locale (see \fBlocaltime\fP). \fBWeek\-ago\fP means 1 second after midnight exactly 7 days ago. \fBThis\-month\fP means 1 second after midnight on day 1 of the month. \fBThis\-year\fP means the 1 second after midnight on the first day of the first month. .TP .BR \-ts ,\ \-\-start \ [\fIstart-date\fP]\ [\fIstart-time\fP] Search for events with time stamps equal to or after the given start time. The format of start time depends on your locale. You can check the format of your locale by running .B date \(aq+%x\(aq. If the date is omitted, .B today is assumed. If the time is omitted, .B midnight is assumed. Use 24 hour clock time rather than AM or PM to specify time. An example date using the en_US.utf8 locale is 09/03/2009. An example of time is 18:00:00. The date format accepted is influenced by the LC_TIME environmental variable. You may also use the word: \fBnow\fP, \fBrecent\fP, \fBthis-hour\fP, \fBboot\fP, \fBtoday\fP, \fByesterday\fP, \fBthis\-week\fP, \fBweek\-ago\fP, \fBthis\-month\fP, \fBthis\-year\fP, or \fBcheckpoint\fP. \fBBoot\fP means the time of day to the second when the system last booted. \fBToday\fP means starting at 1 second after midnight. \fBRecent\fP is 10 minutes ago. \fBYesterday\fP is 1 second after midnight the previous day. \fBThis\-week\fP means starting 1 second after midnight on day 0 of the week determined by your locale (see \fBlocaltime\fP). \fBWeek\-ago\fP means starting 1 second after midnight exactly 7 days ago. \fBThis\-month\fP means 1 second after midnight on day 1 of the month. \fBThis\-year\fP means the 1 second after midnight on the first day of the first month. .sp \fBcheckpoint\fP means \fIausearch\fP will use the timestamp found within a valid checkpoint file ignoring the recorded inode, device, serial, node and event type also found within a checkpoint file. Essentially, this is the recovery action should an invocation of \fIausearch\fP with a checkpoint option fail with an exit status of 10, 11 or 12. It could be used in a shell script something like: .sp .in +5 .nf .na ausearch --checkpoint /etc/audit/auditd_checkpoint.txt -i _au_status=$? if test ${_au_status} eq 10 -o ${_au_status} eq 11 -o ${_au_status} eq 12 then ausearch --checkpoint /etc/audit/auditd_checkpoint.txt --start checkpoint -i fi .ad .fi .in -5 .TP .BR \-tm ,\ \-\-terminal \ \fIterminal\fP Search for an event matching the given \fIterminal\fP value. Some daemons such as cron and atd use the daemon name for the terminal. .TP .BR \-ua ,\ \-\-uid\-all \ \fIall-user-id\fP Search for an event with either user ID, effective user ID, or login user ID (auid) matching the given \fIuser ID\fP. .TP .BR \-ue ,\ \-\-uid\-effective \ \fIeffective-user-id\fP Search for an event with the given \fIeffective user ID\fP. .TP .BR \-ui ,\ \-\-uid \ \fIuser-id\fP Search for an event with the given \fIuser ID\fP. .TP .BR \-ul ,\ \-\-loginuid \ \fIlogin-id\fP Search for an event with the given \fIlogin user ID\fP. All entry point programs that are PAMified need to be configured with pam_loginuid required for the session for searching on loginuid (auid) to be accurate. .TP .BR \-uu ,\ \-\-uuid \ \fIguest-uuid\fP Search for an event with the given \fIguest UUID\fP. .TP .BR \-v ,\ \-\-version Print the version and exit .TP .BR \-vm ,\ \-\-vm-name \ \fIguest-name\fP Search for an event with the given \fIguest name\fP. .TP .BR \-w ,\ \-\-word String based matches must match the whole word. This category of matches include: filename, hostname, terminal, keys, and SE Linux context. .TP .BR \-x ,\ \-\-executable \ \fIexecutable\fP Search for an event matching the given \fIexecutable\fP name. .SH "EXIT STATUS" .TP 5 0 if OK, .TP 1 if nothing found, or argument errors or minor file access/read errors, .TP 10 invalid checkpoint data found in checkpoint file, .TP 11 checkpoint processing error .TP 12 checkpoint event not found in matching log file .SH NOTE The boot time option is a convenience function and has limitations. The time it calculates is based on time now minus /proc/uptime. If after boot the system clock has been adjusted, perhaps by ntp, then the calculation may be wrong. In that case you'll need to fully specify the time. You can check the time it would use by running: date -d "`cut \-f1 \-d. /proc/uptime` seconds ago" .SH EXAMPLES .nf Search for a specific user: # ausearch \-\-start today \-\-loginuid john \-i Check the SELinux log for any denials today # ausearch \-\-start today \-m avc \-i Output any recent SELinux log # ausearch \-m avc,user_avc,selinux_err,user_selinux_err \-i \-ts recent Output logs in text format # ausearch \-\-start today \-\-format text Output TTY events interpreted and shell escaped # ausearch \-\-start today \-m TTY \-i \-\-escape shell_quote .SH "SEE ALSO" .BR auditd (8), .BR auditd.conf (5), .BR aureport (8), .BR pam_loginuid (8). audit-userspace-4.0.5/docs/ausearch_add_expression.3000066400000000000000000000034101501761310600225120ustar00rootroot00000000000000.TH "AUSEARCH_ADD_EXPRESSION" "3" "Feb 2008" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_expression \- build up search expression .SH "SYNOPSIS" .B #include \fBint ausearch_add_expression(auparse_state_t *\fIau\fB, const char *\fIexpression\fB, char **\fIerror\fB, ausearch_rule_t \fIhow\fB);\fR .SH "DESCRIPTION" .B ausearch_add_item adds an expression to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The .I expression parameter contains an expression, as specified in .BR ausearch\-expression (5). The .I how parameter determines how this search expression will affect the existing search expression, if one is already defined. The possible values are: .RS .TP .I AUSEARCH_RULE_CLEAR Clear the current search expression, if any, and use only this search expression. .TP .I AUSEARCH_RULE_OR If a search expression .I E is already configured, replace it by \fB(\fIE\fB || \fIthis_search_expression\fB)\fR. .TP .I AUSEARCH_RULE_AND If a search expression .I E is already configured, replace it by \fB(\fIE\fB && \fIthis_search_expression\fB)\fR. .RE .SH "RETURN VALUE" If successful, .B ausearch_add_expression returns 0. Otherwise, it returns \-1, sets .B errno and it may set \fB*\fIerror\fR to an error message; the caller must free the error message using .BR free (3). If an error message is not available or can not be allocated, \fB*\fIerror\fR is set to \fBNULL\fR. .SH "SEE ALSO" .BR ausearch_add_item (3), .BR ausearch_add_interpreted_item (3), .BR ausearch_add_timestamp_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR ausearch\-expression (5). .SH AUTHOR Miloslav Trmac audit-userspace-4.0.5/docs/ausearch_add_interpreted_item.3000066400000000000000000000037751501761310600236740ustar00rootroot00000000000000.TH "AUSEARCH_ADD_INTERPRETED_ITEM" "3" "Nov 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_interpreted_item \- build up search rule .SH "SYNOPSIS" .B #include .sp int ausearch_add_interpreted_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how); .SH "DESCRIPTION" ausearch_add_interpreted_item adds one search condition to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The field value is the field name that the value will be checked for. The op variable describes what kind of check is to be done. Legal op values are: .RS .TP .I "exists" just check that a field name exists .TP .I "=" locate the field name and check that the value associated with it is equal to the value given in this rule. .TP .I "!=" locate the field name and check that the value associated with it is NOT equal to the value given in this rule. .RE The value parameter is compared to the interpreted field value (the value that would be returned by \fBauparse_interpret_field\fR(3)). The how value determines how this search condition will affect the existing search expression if one is already defined. The possible values are: .RS .TP .I AUSEARCH_RULE_CLEAR Clear the current search expression, if any, and use only this search condition. .TP .I AUSEARCH_RULE_OR If a search expression .I E is already configured, replace it by \fB(\fIE\fB || \fIthis_search_condition\fB)\fR. .TP .I AUSEARCH_RULE_AND If a search expression .I E is already configured, replace it by \fB(\fIE\fB && \fIthis_search_condition\fB)\fR. .RE .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR ausearch_add_expression (3), .BR ausearch_add_item (3), .BR ausearch_add_timestamp_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR ausearch\-expression (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/ausearch_add_item.3000066400000000000000000000040561501761310600212600ustar00rootroot00000000000000.TH "AUSEARCH_ADD_ITEM" "3" "Feb 2012" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_item \- build up search rule .SH "SYNOPSIS" .B #include .sp int ausearch_add_item(auparse_state_t *au, const char *field, const char *op, const char *value, ausearch_rule_t how); .SH "DESCRIPTION" ausearch_add_item adds one search condition to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The field value is the field name that the value will be checked for. The op variable describes what kind of check is to be done. Legal op values are: .RS .TP .I "exists" just check that a field name exists .TP .I "=" locate the field name and check that the value associated with it is equal to the value given in this rule. .TP .I "!=" locate the field name and check that the value associated with it is NOT equal to the value given in this rule. .RE The value parameter is compared to the uninterpreted field value. If you are trying to match against a field who's type is AUPARSE_TYPE_ESCAPED, you will want to use the ausearch_add_interpreted_item() function instead. The how value determines how this search condition will affect the existing search expression if one is already defined. The possible values are: .RS .TP .I AUSEARCH_RULE_CLEAR Clear the current search expression, if any, and use only this search condition. .TP .I AUSEARCH_RULE_OR If a search expression .I E is already configured, replace it by \fB(\fIE\fB || \fIthis_search_condition\fB)\fR. .TP .I AUSEARCH_RULE_AND If a search expression .I E is already configured, replace it by \fB(\fIE\fB && \fIthis_search_condition\fB)\fR. .RE .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR ausearch_add_expression (3), .BR ausearch_add_interpreted_item (3), .BR ausearch_add_timestamp_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR ausearch\-expression (5). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/ausearch_add_regex.3000066400000000000000000000020161501761310600214260ustar00rootroot00000000000000.TH "AUSEARCH_ADD_REGEX" "3" "Sept 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_regex \- use regular expression search rule .SH "SYNOPSIS" .B #include .sp int ausearch_add_regex(auparse_state_t *au, const char *regexp); .SH "DESCRIPTION" ausearch_add_regex adds one search condition based on a regular expression to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The regular expression follows the posix extended regular expression conventions, and is matched against the full record (without interpreting field values). If an existing search expression .I E is already defined, this function replaces it by \fB(\fIE\fB && \fIthis_regexp\fB)\fR. .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR ausearch_add_expression (3), .BR ausearch_add_item (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR regcomp (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/ausearch_add_timestamp_item.3000066400000000000000000000036441501761310600233450ustar00rootroot00000000000000.TH "AUSEARCH_ADD_TIMESTAMP_ITEM" "3" "Aug 2014" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_timestamp_item \- build up search rule .SH "SYNOPSIS" .B #include .sp int ausearch_add_timestamp_item(auparse_state_t *au, const char *op, time_t sec, unsigned milli, ausearch_rule_t how) .SH "DESCRIPTION" ausearch_add_timestamp_item adds an event time condition to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The op parameter specifies the desired comparison. Legal op values are \fI<\fR, \fI<=\fR, \fI>=\fR, \fI>\fR and \fI=\fR. The left operand of the comparison operator is the timestamp of the examined event, the right operand is specified by the sec and milli parameters. The how value determines how this search condition will affect the existing search expression if one is already defined. The possible values are: .RS .TP .I AUSEARCH_RULE_CLEAR Clear the current search expression, if any, and use only this search condition. .TP .I AUSEARCH_RULE_OR If a search expression .I E is already configured, replace it by \fB(\fIE\fB || \fIthis_search_condition\fB)\fR. .TP .I AUSEARCH_RULE_AND If a search expression .I E is already configured, replace it by \fB(\fIE\fB && \fIthis_search_condition\fB)\fR. .RE .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH APPLICATION USAGE Use .BR ausearch_add_item (3) and .BR ausearch_add_interpreted_item (3) to add conditions that check audit record fields. Use .BR ausearch_add_expression (3) to add complex search expressions using a single function call. .SH "SEE ALSO" .BR ausearch_add_expression (3), .BR ausearch_add_item (3), .BR ausearch_add_interpreted_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR ausearch\-expression (5). .SH AUTHOR Miloslav Trmac audit-userspace-4.0.5/docs/ausearch_add_timestamp_item_ex.3000066400000000000000000000037071501761310600240410ustar00rootroot00000000000000.TH "AUSEARCH_ADD_TIMESTAMP_ITEM_EX" "3" "Aug 2014" "Red Hat" "Linux Audit API" .SH NAME ausearch_add_timestamp_item_ex \- build up search rule .SH "SYNOPSIS" .B #include .sp int ausearch_add_timestamp_item_ex(auparse_state_t *au, const char *op, time_t sec, unsigned milli, unsigned serial, ausearch_rule_t how) .SH "DESCRIPTION" ausearch_add_timestamp_item adds an event time condition to the current audit search expression. The search conditions can then be used to scan logs, files, or buffers for something of interest. The op parameter specifies the desired comparison. Legal op values are \fI<\fR, \fI<=\fR, \fI>=\fR, \fI>\fR and \fI=\fR. The left operand of the comparison operator is the timestamp of the examined event, the right operand is specified by the sec, milli, and serial parameters. The how value determines how this search condition will affect the existing search expression if one is already defined. The possible values are: .RS .TP .I AUSEARCH_RULE_CLEAR Clear the current search expression, if any, and use only this search condition. .TP .I AUSEARCH_RULE_OR If a search expression .I E is already configured, replace it by \fB(\fIE\fB || \fIthis_search_condition\fB)\fR. .TP .I AUSEARCH_RULE_AND If a search expression .I E is already configured, replace it by \fB(\fIE\fB && \fIthis_search_condition\fB)\fR. .RE .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH APPLICATION USAGE Use .BR ausearch_add_item (3) and .BR ausearch_add_interpreted_item (3) to add conditions that check audit record fields. Use .BR ausearch_add_expression (3) to add complex search expressions using a single function call. .SH "SEE ALSO" .BR ausearch_add_expression (3), .BR ausearch_add_item (3), .BR ausearch_add_interpreted_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3), .BR ausearch_clear (3), .BR ausearch_next_event (3), .BR ausearch_cur_event (3), .BR ausearch\-expression (5). .SH AUTHOR Miloslav Trmac audit-userspace-4.0.5/docs/ausearch_clear.3000066400000000000000000000007071501761310600205770ustar00rootroot00000000000000.TH "AUSEARCH_CLEAR" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_clear \- clear search parameters .SH "SYNOPSIS" .B #include .sp void ausearch_clear(auparse_state_t *au); .SH "DESCRIPTION" ausearch_clear clears any search parameters stored in the parser instance and frees memory associated with it. .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR ausearch_add_item (3), .BR ausearch_add_regex (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/ausearch_cur_event.3000066400000000000000000000014551501761310600215040ustar00rootroot00000000000000.TH "AUSEARCH_CUR_EVENT" "3" "Feb 2024" "Red Hat" "Linux Audit API" .SH NAME ausearch_cur_event \- check if the current event meets search criteria .SH "SYNOPSIS" .B #include .sp int ausearch_cur_event(auparse_state_t *au); .SH "DESCRIPTION" ausearch_cur_event will scan the input source and evaluate whether any record in the current event contains the data being searched for. Evaluation is done at the record level. If a match is found, the cursor is repositioned; otherwise, it remains on the last successfully parsed record within the current event. .SH "RETURN VALUE" Returns \-1 if an error occurs, 0 if no matches, and 1 for success. .SH "SEE ALSO" .BR ausearch_add_item (3), .BR ausearch_add_regex (3), .BR ausearch_next_event (3), .BR ausearch_set_stop (3). .SH AUTHOR Attila Lakatos audit-userspace-4.0.5/docs/ausearch_next_event.3000066400000000000000000000012001501761310600216550ustar00rootroot00000000000000.TH "AUSEARCH_NEXT_EVENT" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_next_event \- find the next event that meets search criteria .SH "SYNOPSIS" .B #include .sp int ausearch_next_event(auparse_state_t *au); .SH "DESCRIPTION" ausearch_next_event will scan the input source and evaluate whether any record in an event contains the data being searched for. Evaluation is done at the record level. .SH "RETURN VALUE" Returns \-1 if an error occurs, 0 if no matches, and 1 for success. .SH "SEE ALSO" .BR ausearch_add_item (3), .BR ausearch_add_regex (3), .BR ausearch_set_stop (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/ausearch_set_stop.3000066400000000000000000000020011501761310600213360ustar00rootroot00000000000000.TH "AUSEARCH_SET_STOP" "3" "Feb 2007" "Red Hat" "Linux Audit API" .SH NAME ausearch_set_stop \- set the cursor position .SH "SYNOPSIS" .B #include .sp int ausearch_set_stop(auparse_state_t *au, austop_t where); .SH "DESCRIPTION" ausearch_set_stop determines where the internal cursor will stop when a search condition is met. The possible values are: .RS .TP .I AUSEARCH_STOP_EVENT This one repositions the cursors to the first field of the first record of the event containing the items searched for. .TP .I AUSEARCH_STOP_RECORD This one repositions the cursors to the first field of the record containing the items searched for. .TP .I AUSEARCH_STOP_FIELD This one simply stops on the current field when the evaluation of the rules becomes true. .RE .SH "RETURN VALUE" Returns \-1 if an error occurs; otherwise, 0 for success. .SH "SEE ALSO" .BR ausearch_add_item (3), .BR ausearch_add_regex (3), .BR ausearch_clear (3), .BR ausearch_cur_event (3), .BR ausearch_next_event (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/get_auditfail_action.3000066400000000000000000000043751501761310600220010ustar00rootroot00000000000000.\" Copyright (C) 2006 HP .\" This file is distributed according to the GNU General Public License. .\" See the file COPYING in the top level source directory for details. .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "GET_AUDITFAIL_ACTION" 3 "2006-7-10" "Linux 2.7" "Linux Programmer's Manual" .SH NAME get_auditfail_action \- Get failure_action tunable value .SH "SYNOPSIS" .ad l .hy 0 #include .sp .HP 19 int\ \fBget_auditfail_action\fR(auditfail_t *\fIfailmode\fR); .ad .hy .SH "DESCRIPTION" .PP This function gets the failure_action tunable value stored in \fB/etc/libaudit.conf\fR. \fBget_auditfail_action\fR should be called after an \fBaudit_open\fR call returns an error to see what action the admin prefers. .PP The failure_action value found in \fB/etc/libaudit.conf\fR is copied into the \fIfailmode\fR argument upon function return. This value should then be used by the calling application to determine what action should be taken when the audit subsystem is unavailable. .SH "RETURN VALUE" .PP Upon success, \fBget_auditfail_action\fR returns a zero, and the \fIfailmode\fR argument will hold the failure_action value. The possible values for failure_action are: FAIL_IGNORE (0), FAIL_LOG (1), and FAIL_TERMINATE (2). Upon failure, \fBget_auditfail_action\fR returns a return code of one. .SH "ERRORS" .PP An error is returned if there is an error reading \fB/etc/libaudit.conf\fR or if the failure_action tunable is not found in the file. .SH "EXAMPLES" .PP /* Sample code */ auditfail_t failmode; if ((fd = audit_open() ) < 0 ) { fprintf (stderr, "Cannot open netlink audit socket"); /* Get the failure_action */ if ((rc = get_auditfail_action(&failmode)) == 0) { if (failmode == FAIL_LOG) fprintf (stderr, "Audit subsystem unavailable"); else if (failmode == FAIL_TERMINATE) exit (1); /* If failmode == FAIL_IGNORE, do nothing */ } } .SH "SEE ALSO" .BR audit_open (3), .BR auditd (8). .SH AUTHOR Lisa M. Smith. audit-userspace-4.0.5/docs/libaudit.conf.5000066400000000000000000000017661501761310600203670ustar00rootroot00000000000000.TH LIBAUDIT.CONF "5" "Oct 2009" "Red Hat" "System Administration Utilities" .SH NAME libaudit.conf \- libaudit configuration file .SH DESCRIPTION The file .I /etc/libaudit.conf contains configuration information for user space applications that link to libaudit. The applications are responsible for querying the settings in this file and obeying the admin's preferences. This file contains one configuration keyword per line, an equal sign, and then followed by appropriate configuration information. The keywords recognized are: .IR failure_action ". These keywords are described below. .TP .I failure_action This keyword specifies what action the admin wishes a user space application to take when there is a failure to send an audit event to the kernel. The possible values are: .IR IGNORE - meaning do nothing, .IR LOG - write to syslog the inability to send an audit event, and .I TERMINATE - the user space application should exit. .SH "SEE ALSO" .BR get_auditfail_action (3). .SH AUTHOR Steve Grubb audit-userspace-4.0.5/docs/set_aumessage_mode.3000066400000000000000000000024321501761310600214640ustar00rootroot00000000000000.\" Copyright (C) 2004 IBM .\" This file is distributed according to the GNU General Public License. .\" See the file COPYING in the top level source directory for details. .de Sh \" Subsection .br .if t .Sp .ne 5 .PP \fB\\$1\fR .PP .. .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Ip \" List item .br .ie \\n(.$>=3 .ne \\$3 .el .ne 3 .IP "\\$1" \\$2 .. .TH "SET_AUMESSAGE_MODE" 3 "2004-12-01" "Linux 2.6" "Linux Programmer's Manual" .SH NAME set_aumessage_mode \- Sets the message mode .SH "SYNOPSIS" .ad l .hy 0 #include .sp .HP 23 void\ \fBset_aumessage_mode\fR(message_t\ \fImode\fR, debug_message_t\ \fIdebug\fR); .ad .hy .SH "DESCRIPTION" .PP \fBset_aumessage_mode\fR sets the location where messages are sent and the output of the debug messages. If \fImode\fR=MSG_STDERR, then messages are sent to stderr. If \fImode\fR=MSG_SYSLOG, then messages are sent to syslog. If \fImode\fR=MSG_QUIET (default), then messages are not sent. If \fIdebug\fR=DBG_YES, then debug messages are output. If \fIdebug\fR=DBG_NO (default), then debug messages are not output. .SH "EXAMPLE" .nf /* Sample code */ set_aumessage_mode(MSG_SYSLOG, DBG_YES) .fi .SH "RETURN VALUE" None. .SH "SEE ALSO" .BR auditd (8), .BR audit_open (3). .SH AUTHOR Debora Velarde. audit-userspace-4.0.5/docs/zos-remote.conf.5000066400000000000000000000051201501761310600206620ustar00rootroot00000000000000.\" Copyright (c) International Business Machines Corp., 2007 .\" .\" This program is free software; you can redistribute it and/or .\" modify it under the terms of the GNU General Public License as .\" published by the Free Software Foundation; either version 2 of .\" the License, or (at your option) any later version. .\" .\" This program is distributed in the hope that it will be useful, .\" but WITHOUT ANY WARRANTY; without even the implied warranty of .\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See .\" the GNU General Public License for more details. .\" .\" You should have received a copy of the GNU General Public License .\" along with this program; if not, write to the Free Software .\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, .\" MA 02111-1307 USA .\" .\" Changelog: .\" 2007-10-06, created by Klaus Heinrich Kiwi .\" .TH ZOS\-REMOTE.CONF 5 "Oct 2007" "IBM" "System Administration Utilities" .SH NAME zos\-remote.conf \- the audisp-racf plugin configuration file .SH DESCRIPTION .B zos\-remote.conf controls the configuration for the .BR audispd\-zos\-remote (8) Audit dispatcher plugin. The default location for this file is .IR /etc/audit/zos\-remote.conf , however, a different file can be specified as the first argument to the .B audispd\-zos\-remote plugin. See .BR audispd\-zos\-remote (8) and .BR auditd (8). The options available are as follows: .TP .I server This is the IBM z/OS ITDS server hostname or IP address .TP .I port The port number where ITDS is running on the z/OS server. Default is 389 (ldap port) .TP .I user The z/OS RACF user ID which the audispd\-zos\-remote plugin will use to perform Remote Audit requests. This user needs READ access to FACILITY Class resource IRR.LDAP.REMOTE.AUDIT (See .BR audispd\-zos\-remote (8)). .TP .I password The password associated the the z/OS user ID configured above. .TP .I timeout The number in seconds that .B audispd\-zos\-remote plugin will wait before giving up in connection attempts and event submissions. The default value is 15 .TP .I q_depth The .B audispd\-zos\-remote plugin will queue inputted events to the maximum of .I q_depth events while trying to submit those remotely. This can handle burst of events or in case of a slow network connection. However, the .B audispd\-zos\-remote plugin will drop events in case the queue is full. The default queue depth is 64 - Increase this value in case you are experiencing event drop due to full queue .RB ( audispd\-zos\-remote will log this to syslog). .SH "SEE ALSO" .BR audispd\-zos\-remote (8) .SH AUTHOR Klaus Heinrich Kiwi audit-userspace-4.0.5/init.d/000077500000000000000000000000001501761310600160035ustar00rootroot00000000000000audit-userspace-4.0.5/init.d/Makefile.am000066400000000000000000000062601501761310600200430ustar00rootroot00000000000000# Makefile.am-- # Copyright 2004-2025 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig CLEANFILES = $(BUILT_SOURCES) EXTRA_DIST = auditd.service.in audit-rules.service.in auditd.conf auditd.cron \ audit-tmpfiles.conf \ libaudit.conf auditd.condrestart \ auditd.reload auditd.restart auditd.resume \ auditd.rotate auditd.state auditd.stop audit-rules.service \ audit-stop.rules augenrules libconfig = libaudit.conf initdir = $(prefix)/lib/systemd/system legacydir = $(libexecdir)/initscripts/legacy-actions/auditd auditdir = $(sysconfdir)/audit auditrdir = $(auditdir)/rules.d dist_audit_DATA = auditd.conf audit-stop.rules sbin_SCRIPTS = augenrules BUILT_SOURCES = auditd.service audit-rules.service %.service: %.service.in Makefile $(AM_V_GEN)sed \ -e 's![@]runstatedir[@]!$(runstatedir)!' \ -e 's![@]sbindir[@]!$(sbindir)!' \ -e 's![@]sysconfdir[@]!$(sysconfdir)!' \ $< > $@ install-data-hook: $(INSTALL_DATA) -D -m 640 ${srcdir}/${libconfig} ${DESTDIR}${sysconfdir} mkdir -p ${DESTDIR}$(prefix)/lib/tmpfiles.d/ $(INSTALL_DATA) -m 640 ${srcdir}/audit-tmpfiles.conf ${DESTDIR}$(prefix)/lib/tmpfiles.d/audit.conf install-exec-hook: mkdir -p ${DESTDIR}${initdir} mkdir -p ${DESTDIR}${legacydir} $(INSTALL_SCRIPT) -D -m 644 ${builddir}/auditd.service ${DESTDIR}${initdir} $(INSTALL_SCRIPT) -D -m 644 ${builddir}/audit-rules.service ${DESTDIR}${initdir} $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.rotate ${DESTDIR}${legacydir}/rotate $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.resume ${DESTDIR}${legacydir}/resume $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.reload ${DESTDIR}${legacydir}/reload $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.state ${DESTDIR}${legacydir}/state $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.stop ${DESTDIR}${legacydir}/stop $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.restart ${DESTDIR}${legacydir}/restart $(INSTALL_SCRIPT) -D -m 750 ${srcdir}/auditd.condrestart ${DESTDIR}${legacydir}/condrestart chmod 0755 $(DESTDIR)$(sbindir)/augenrules uninstall-hook: rm ${DESTDIR}${sysconfdir}/${libconfig} rm ${DESTDIR}${initdir}/auditd.service rm ${DESTDIR}${initdir}/audit-rules.service rm ${DESTDIR}${legacydir}/rotate rm ${DESTDIR}${legacydir}/resume rm ${DESTDIR}${legacydir}/reload rm ${DESTDIR}${legacydir}/state rm ${DESTDIR}${legacydir}/stop rm ${DESTDIR}${legacydir}/restart rm ${DESTDIR}${legacydir}/condrestart rm ${DESTDIR}$(prefix)/lib/tmpfiles.d/audit.conf audit-userspace-4.0.5/init.d/audit-rules.service.in000066400000000000000000000016631501761310600222360ustar00rootroot00000000000000[Unit] Description=Load Audit Rules ConditionKernelCommandLine=!audit=0 ConditionKernelCommandLine=!audit=off DefaultDependencies=no # We need the local file system for the rules. Augenrules uses /tmp while # constructing rules, so we have to wait for that to be available, too. After=local-fs.target systemd-tmpfiles-setup.service Documentation=man:auditctl(8) https://github.com/linux-audit/audit-documentation [Service] Type=oneshot ExecStart=@sbindir@/augenrules --load # By default we don't clear the rules on exit. To enable this, uncomment the # next line after copying the file to /etc/systemd/system/audit-rules.service #ExecStopPost=@sbindir@/auditctl -R @sysconfdir@/audit/audit-stop.rules ### Security Settings ### # This won't use any security settings. They tend to interfere with # loading rules anyways. Since its a one-shot service with root owned # input, let's just load and get done. [Install] WantedBy=multi-user.target audit-userspace-4.0.5/init.d/audit-stop.rules000066400000000000000000000001771501761310600211550ustar00rootroot00000000000000# These rules are loaded when the audit daemon stops # if configured to do so. # Disable auditing -e 0 # Delete all rules -D audit-userspace-4.0.5/init.d/audit-tmpfiles.conf000066400000000000000000000000441501761310600215770ustar00rootroot00000000000000d /var/log/audit 0700 root root - - audit-userspace-4.0.5/init.d/auditd.condrestart000066400000000000000000000004311501761310600215250ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd. state=$(systemctl show -P ActiveState auditd) if [ "$state" = "active" ] ; then /sbin/auditctl --signal stop /bin/systemctl start auditd RETVAL="$?" exit $RETVAL fi exit 0 audit-userspace-4.0.5/init.d/auditd.conf000066400000000000000000000016061501761310600201270ustar00rootroot00000000000000# # This file controls the configuration of the audit daemon # local_events = yes write_logs = yes log_file = /var/log/audit/audit.log log_group = root log_format = ENRICHED flush = INCREMENTAL_ASYNC freq = 50 max_log_file = 8 num_logs = 5 priority_boost = 4 name_format = NONE ##name = mydomain max_log_file_action = ROTATE space_left = 75 space_left_action = SYSLOG verify_email = yes action_mail_acct = root admin_space_left = 50 admin_space_left_action = SUSPEND disk_full_action = SUSPEND disk_error_action = SUSPEND report_interval = 0 use_libwrap = yes ##tcp_listen_port = 60 tcp_listen_queue = 5 tcp_max_per_addr = 1 ##tcp_client_ports = 1024-65535 tcp_client_max_idle = 0 transport = TCP krb5_principal = auditd ##krb5_key_file = /etc/audit/audit.key distribute_network = no q_depth = 2000 overflow_action = SYSLOG max_restarts = 10 plugin_dir = /etc/audit/plugins.d end_of_event_timeout = 2 audit-userspace-4.0.5/init.d/auditd.cron000066400000000000000000000005141501761310600201400ustar00rootroot00000000000000#!/bin/sh ########## # This script can be installed to the cron system to get log rotation # based on time instead of log size. ########## /sbin/auditctl --signal rotate EXITVALUE=$? if [ $EXITVALUE != 0 ]; then /usr/bin/logger -t auditd "ALERT auditctl exited abnormally with [$EXITVALUE] while rotating the logs" fi exit 0 audit-userspace-4.0.5/init.d/auditd.reload000066400000000000000000000004401501761310600204430ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd # Check that we are root ... so non-root users stop here test "$(id -u)" = "0" || exit 4 printf "Reconfiguring auditd: " /sbin/auditctl --signal reload RETVAL=$? echo exit $RETVAL audit-userspace-4.0.5/init.d/auditd.restart000066400000000000000000000004671501761310600206720ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd. test -f /etc/audit/auditd.conf || exit 6 /sbin/auditctl --signal stop sleep 1 echo "Redirecting start to /bin/systemctl start auditd.service" /bin/systemctl start auditd.service RETVAL="$?" exit $RETVAL audit-userspace-4.0.5/init.d/auditd.resume000066400000000000000000000004341501761310600205000ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd # Check that we are root ... so non-root users stop here test "$(id -u)" = "0" || exit 4 printf "Resuming logging: " /sbin/auditctl --signal resume RETVAL=$? echo exit $RETVAL audit-userspace-4.0.5/init.d/auditd.rotate000066400000000000000000000004311501761310600204730ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd # Check that we are root ... so non-root users stop here test "$(id -u)" = "0" || exit 4 printf "Rotating logs: " /sbin/auditctl --signal rotate RETVAL=$? echo exit $RETVAL audit-userspace-4.0.5/init.d/auditd.service.in000066400000000000000000000036671501761310600212600ustar00rootroot00000000000000[Unit] Description=Security Audit Logging Service ConditionKernelCommandLine=!audit=0 ConditionKernelCommandLine=!audit=off DefaultDependencies=no ## The following is a "Wants" so that if rules don't load, it will ## not fail starting the main service. This indicates a weaker dependency. Wants=audit-rules.service ## If auditd is sending or receiving remote logging, copy this file to ## /etc/systemd/system/auditd.service and comment out the first After and ## uncomment the second so that network-online.target is part of After. ## then comment the first Before and uncomment the second Before to remove ## sysinit.target from "Before". Finish by removing everything else leaving ## a minimal file that overrides only the necessary lines but inherits the ## original settings in case they get updated by a distribution. Please check ## systemd documentation if it's unclear how to override settings. ## If using remote logging, ensure that the systemd-update-utmp.service file ## is updated to remove the After=auditd.service directive to prevent a ## boot-time ordering cycle. After=local-fs.target systemd-tmpfiles-setup.service #After=network-online.target local-fs.target systemd-tmpfiles-setup.service Before=sysinit.target shutdown.target audit-rules.service #Before=shutdown.target Conflicts=shutdown.target RefuseManualStop=yes Documentation=man:auditd(8) https://github.com/linux-audit/audit-documentation [Service] Type=forking PIDFile=@runstatedir@/auditd.pid ExecStart=@sbindir@/auditd Restart=on-failure ## Do not restart for intentional exits. See EXIT CODES section in auditd(8). RestartPreventExitStatus=2 4 6 ### Security Settings ### MemoryDenyWriteExecute=true LockPersonality=true ## The following control prevents rules on /proc so its off by default #ProtectControlGroups=true ## The following control prevents rules on /usr/lib/modules/ its off by default #ProtectKernelModules=true RestrictRealtime=true [Install] WantedBy=multi-user.target audit-userspace-4.0.5/init.d/auditd.state000066400000000000000000000007321501761310600203210ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd # Check that we are root ... so non-root users stop here test "$(id -u)" = "0" || exit 4 PATH=/sbin:/bin:/usr/bin:/usr/sbin state_file="/var/run/auditd.state" printf "Getting auditd internal state: " /sbin/auditctl --signal state RETVAL=$? sleep 1 if [ $RETVAL -eq 0 ] ; then if [ -e $state_file ] ; then printf "\n\n" cat $state_file fi fi echo exit $RETVAL audit-userspace-4.0.5/init.d/auditd.stop000066400000000000000000000004041501761310600201620ustar00rootroot00000000000000#!/bin/sh # Helper script to provide legacy auditd service options not # directly supported by systemd # Check that we are root ... so non-root users stop here test "$(id -u)" = "0" || exit 4 echo "Stopping logging: " /sbin/auditctl --signal stop exit $? audit-userspace-4.0.5/init.d/augenrules000066400000000000000000000100561501761310600201020ustar00rootroot00000000000000#!/bin/sh # Script to concatenate rules files found in a base audit rules directory # to form a single /etc/audit/audit.rules file suitable for loading into # the Linux audit system # When forming the interim rules file, both empty lines and comment # lines (starting with # or #) are stripped as the source files # are processed. # # Having formed the interim rules file, the script checks if the file is empty # or is identical to the existing /etc/audit/audit.rules and if either of # these cases are true, it does not replace the existing file # # Variables # # DestinationFile: # Destination rules file # SourceRulesDir: # Directory location to find component rule files # TmpRules: # Temporary interim rules file # ASuffix: # Suffix for previous audit.rules file if this script replaces it. # The file is left in the destination directory with suffix with $ASuffix DestinationFile=/etc/audit/audit.rules SourceRulesDir=/etc/audit/rules.d TmpRules=$(mktemp /tmp/aurules.XXXXXXXX) ASuffix="prev" OnlyCheck=0 LoadRules=0 RETVAL=0 cmd="$0" usage="Usage: $cmd [--check|--load]" # Delete the interim file on faults trap 'rm -f ${TmpRules}; exit 1' HUP INT QUIT PIPE TERM try_load() { if [ $LoadRules -eq 1 ] ; then /sbin/auditctl -R ${DestinationFile} RETVAL=$? fi } # Check if audit is in immutable mode - exit if so check_immutable () { if [ "$(auditctl -s | awk '$1 == "enabled" { print $2 }')" = "2" ] ; then echo "$cmd: Audit system is in immutable mode - exiting with no changes" exit 0 fi } while [ $# -ge 1 ] do if [ "$1" = "--check" ] ; then OnlyCheck=1 elif [ "$1" = "--load" ] ; then LoadRules=1 else echo "$usage" exit 1 fi shift done # Check environment if [ ! -d ${SourceRulesDir} ]; then echo "$cmd: No rules directory - ${SourceRulesDir}" rm -f "${TmpRules}" try_load exit 1 fi # Create the interim rules file ensuring its access modes protect it # from normal users and strip empty lines and comment lines. We also ensure # - the last processed -D directive without an option is emitted as the first # line. -D directives with options are left in place # - the last processed -b directory is emitted as the second line # - the last processed -f directory is emitted as the third line # - the last processed -e directive is emitted as the last line umask 0137 echo "## This file is automatically generated from $SourceRulesDir" >> "${TmpRules}" for rules in $(/bin/ls -1v ${SourceRulesDir} | grep "\.rules$") ; do cat ${SourceRulesDir}/"${rules}" done | awk ' BEGIN { minus_e = ""; minus_D = ""; minus_f = ""; minus_b = ""; rest = 0; } { sub(/\r$/, ""); if (length($0) < 1) { next; } if (match($0, "^\\s*#")) { next; } if (match($0, "^\\s*-e")) { minus_e = $0; next; } if (match($0, "^\\s*-D\\s*$")) { minus_D = $0; next; } if (match($0, "^\\s*-f")) { minus_f = $0; next; } if (match($0, "^\\s*-b")) { minus_b = $0; next; } rules[rest++] = $0; } END { printf "%s\n%s\n%s\n", minus_D, minus_b, minus_f; for (i = 0; i < rest; i++) { printf "%s\n", rules[i]; } printf "%s\n", minus_e; }' >> "${TmpRules}" # If empty then quit if [ ! -s "${TmpRules}" ]; then echo "$cmd: No rules" rm -f "${TmpRules}" try_load exit $RETVAL fi # If the same then quit cmp -s "${TmpRules}" ${DestinationFile} > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "$cmd: No change" rm -f "${TmpRules}" check_immutable try_load exit $RETVAL elif [ $OnlyCheck -eq 1 ] ; then echo "$cmd: Rules have changed and should be updated" rm -f "${TmpRules}" exit 0 fi # Otherwise we install the new file check_immutable if [ -f ${DestinationFile} ]; then cp ${DestinationFile} ${DestinationFile}.${ASuffix} fi # We copy the file so that it gets the right selinux label cp "${TmpRules}" ${DestinationFile} chmod 0640 ${DestinationFile} # Restore context on MLS system. /tmp is SystemLow & audit.rules is SystemHigh if [ -x /usr/sbin/restorecon ] ; then /usr/sbin/restorecon -F ${DestinationFile} fi rm -f "${TmpRules}" try_load exit $RETVAL audit-userspace-4.0.5/init.d/libaudit.conf000066400000000000000000000002771501761310600204550ustar00rootroot00000000000000# This is the configuration file for libaudit tunables. # It is currently only used for the failure_action tunable. # failure_action can be: log, ignore, terminate failure_action = ignore audit-userspace-4.0.5/lib/000077500000000000000000000000001501761310600153645ustar00rootroot00000000000000audit-userspace-4.0.5/lib/.dirstamp000066400000000000000000000000001501761310600171760ustar00rootroot00000000000000audit-userspace-4.0.5/lib/Makefile.am000066400000000000000000000402401501761310600174200ustar00rootroot00000000000000# Makefile.am -- # Copyright 2004-2009,2013-25 Red Hat Inc. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # SUBDIRS = test CLEANFILES = $(BUILT_SOURCES) CONFIG_CLEAN_FILES = *.loT *.rej *.orig EXTRA_DIST = syscall-update.txt gen_tables64.c VERSION_INFO = 1:0 AM_CFLAGS = -fPIC -DPIC -D_GNU_SOURCE ${WFLAGS} AM_CPPFLAGS = -I. -I${top_srcdir} -I${top_srcdir}/auparse -I${top_srcdir}/common pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = audit.pc DISTCLEANFILES = $(pkgconfig_DATA) lib_LTLIBRARIES = libaudit.la include_HEADERS = libaudit.h audit_logging.h audit-records.h libaudit_la_SOURCES = libaudit.c message.c netlink.c \ lookup_table.c audit_logging.c deprecated.c \ audit-fgets.c dso.h private.h errormsg.h libaudit_la_LIBADD = $(CAPNG_LDADD) ${top_builddir}/common/libaucommon.la libaudit_la_DEPENDENCIES = $(libaudit_la_SOURCES) ../config.h ${top_builddir}/common/libaucommon.la libaudit_la_LDFLAGS = -Wl,-z,relro -version-info $(VERSION_INFO) nodist_libaudit_la_SOURCES = $(BUILT_SOURCES) BUILT_SOURCES = actiontabs.h errtabs.h fieldtabs.h flagtabs.h \ fstypetabs.h ftypetabs.h i386_tables.h machinetabs.h \ msg_typetabs.h optabs.h permtabs.h ppc_tables.h s390_tables.h \ s390x_tables.h x86_64_tables.h uringop_tables.h if USE_ARM BUILT_SOURCES += arm_tables.h endif if USE_AARCH64 BUILT_SOURCES += aarch64_tables.h endif if USE_RISCV BUILT_SOURCES += riscv64_tables.h riscv32_tables.h endif noinst_PROGRAMS = gen_actiontabs_h gen_errtabs_h gen_fieldtabs_h \ gen_flagtabs_h gen_fstypetabs_h gen_ftypetabs_h gen_i386_tables_h \ gen_machinetabs_h gen_msg_typetabs_h gen_optabs_h \ gen_permtabs_h gen_ppc_tables_h gen_s390_tables_h \ gen_s390x_tables_h gen_x86_64_tables_h gen_uringop_tables_h if USE_ARM noinst_PROGRAMS += gen_arm_tables_h endif if USE_AARCH64 noinst_PROGRAMS += gen_aarch64_tables_h endif if USE_RISCV noinst_PROGRAMS += gen_riscv64_tables_h gen_riscv32_tables_h endif gen_actiontabs_h_SOURCES = gen_tables.c gen_tables.h actiontab.h gen_actiontabs_h_CFLAGS = '-DTABLE_H="actiontab.h"' $(gen_actiontabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_actiontabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_actiontabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_actiontabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_actiontabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_actiontabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_actiontabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_actiontabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) actiontabs.h: gen_actiontabs_h Makefile ./gen_actiontabs_h --lowercase --i2s --s2i action > $@ if USE_ARM gen_arm_tables_h_SOURCES = gen_tables.c gen_tables.h arm_table.h gen_arm_tables_h_CFLAGS = '-DTABLE_H="arm_table.h"' $(gen_arm_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_arm_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_arm_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_arm_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_arm_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_arm_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_arm_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_arm_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) arm_tables.h: gen_arm_tables_h Makefile ./gen_arm_tables_h --lowercase --i2s --s2i arm_syscall > $@ endif if USE_AARCH64 gen_aarch64_tables_h_SOURCES = gen_tables.c gen_tables.h aarch64_table.h gen_aarch64_tables_h_CFLAGS = '-DTABLE_H="aarch64_table.h"' $(gen_aarch64_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_aarch64_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_aarch64_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_aarch64_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_aarch64_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_aarch64_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_aarch64_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_aarch64_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) aarch64_tables.h: gen_aarch64_tables_h Makefile ./gen_aarch64_tables_h --lowercase --i2s --s2i aarch64_syscall > $@ endif if USE_RISCV gen_riscv64_tables_h_SOURCES = gen_tables.c gen_tables.h riscv64_table.h gen_riscv64_tables_h_CFLAGS = '-DTABLE_H="riscv64_table.h"' $(gen_riscv64_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_riscv64_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_riscv64_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_riscv64_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_riscv64_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_riscv64_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_riscv64_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_riscv64_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) riscv64_tables.h: gen_riscv64_tables_h Makefile ./gen_riscv64_tables_h --lowercase --i2s --s2i riscv64_syscall > $@ gen_riscv32_tables_h_SOURCES = gen_tables.c gen_tables.h riscv32_table.h gen_riscv32_tables_h_CFLAGS = '-DTABLE_H="riscv32_table.h"' $(gen_riscv32_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_riscv32_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_riscv32_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_riscv32_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_riscv32_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_riscv32_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_riscv32_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_riscv32_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) riscv32_tables.h: gen_riscv32_tables_h Makefile ./gen_riscv32_tables_h --lowercase --i2s --s2i riscv32_syscall > $@ endif gen_errtabs_h_SOURCES = gen_tables.c gen_tables.h errtab.h gen_errtabs_h_CFLAGS = '-DTABLE_H="errtab.h"' $(gen_errtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_errtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_errtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_errtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_errtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_errtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_errtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_errtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) errtabs.h: gen_errtabs_h Makefile ./gen_errtabs_h --duplicate-ints --uppercase --i2s --s2i err > $@ gen_fieldtabs_h_SOURCES = gen_tables.c gen_tables.h fieldtab.h gen_fieldtabs_h_CFLAGS = '-DTABLE_H="fieldtab.h"' $(gen_fieldtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_fieldtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_fieldtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_fieldtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_fieldtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_fieldtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_fieldtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_fieldtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) fieldtabs.h: gen_fieldtabs_h Makefile ./gen_fieldtabs_h --duplicate-ints --lowercase --i2s --s2i field > $@ gen_flagtabs_h_SOURCES = gen_tables.c gen_tables.h flagtab.h gen_flagtabs_h_CFLAGS = '-DTABLE_H="flagtab.h"' $(gen_flagtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_flagtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_flagtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_flagtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_flagtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_flagtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_flagtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_flagtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) flagtabs.h: gen_flagtabs_h Makefile ./gen_flagtabs_h --lowercase --i2s --s2i flag > $@ gen_fstypetabs_h_SOURCES = gen_tables.c gen_tables.h fstypetab.h gen_fstypetabs_h_CFLAGS = '-DTABLE_H="fstypetab.h"' $(gen_fstypetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_fstypetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_fstypetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_fstypetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_fstypetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_fstypetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_fstypetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_fstypetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) fstypetabs.h: gen_fstypetabs_h Makefile ./gen_fstypetabs_h --lowercase --i2s --s2i fstype > $@ gen_ftypetabs_h_SOURCES = gen_tables.c gen_tables.h ftypetab.h gen_ftypetabs_h_CFLAGS = '-DTABLE_H="ftypetab.h"' $(gen_ftypetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ftypetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ftypetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ftypetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ftypetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ftypetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ftypetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ftypetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ftypetabs.h: gen_ftypetabs_h Makefile ./gen_ftypetabs_h --lowercase --i2s --s2i ftype > $@ gen_i386_tables_h_SOURCES = gen_tables.c gen_tables.h i386_table.h gen_i386_tables_h_CFLAGS = '-DTABLE_H="i386_table.h"' $(gen_i386_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_i386_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_i386_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_i386_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_i386_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_i386_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_i386_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_i386_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) i386_tables.h: gen_i386_tables_h Makefile ./gen_i386_tables_h --duplicate-ints --lowercase --i2s --s2i \ i386_syscall > $@ gen_machinetabs_h_SOURCES = gen_tables.c gen_tables.h machinetab.h gen_machinetabs_h_CFLAGS = '-DTABLE_H="machinetab.h"' $(gen_machinetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_machinetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_machinetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_machinetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_machinetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_machinetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_machinetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_machinetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) machinetabs.h: gen_machinetabs_h Makefile ./gen_machinetabs_h --duplicate-ints --lowercase --i2s --s2i machine \ > $@ gen_msg_typetabs_h_SOURCES = gen_tables.c gen_tables.h msg_typetab.h gen_msg_typetabs_h_CFLAGS = '-DTABLE_H="msg_typetab.h"' $(gen_msg_typetabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_msg_typetabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_msg_typetabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_msg_typetabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_msg_typetabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_msg_typetabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_msg_typetabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_msg_typetabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) msg_typetabs.h: gen_msg_typetabs_h Makefile ./gen_msg_typetabs_h --uppercase --i2s --s2i msg_type > $@ gen_optabs_h_SOURCES = gen_tables.c gen_tables.h optab.h gen_optabs_h_CFLAGS = '-DTABLE_H="optab.h"' $(gen_optabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_optabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_optabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_optabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_optabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_optabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_optabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_optabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) optabs.h: gen_optabs_h Makefile ./gen_optabs_h --i2s op > $@ gen_permtabs_h_SOURCES = gen_tables.c gen_tables.h permtab.h gen_permtabs_h_CFLAGS = '-DTABLE_H="permtab.h"' $(gen_permtabs_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_permtabs_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_permtabs_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_permtabs_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_permtabs_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_permtabs_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_permtabs_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_permtabs_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) permtabs.h: gen_permtabs_h Makefile ./gen_permtabs_h --lowercase --i2s --s2i perm > $@ gen_ppc_tables_h_SOURCES = gen_tables.c gen_tables.h ppc_table.h gen_ppc_tables_h_CFLAGS = '-DTABLE_H="ppc_table.h"' $(gen_ppc_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_ppc_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_ppc_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_ppc_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_ppc_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_ppc_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_ppc_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_ppc_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) ppc_tables.h: gen_ppc_tables_h Makefile ./gen_ppc_tables_h --lowercase --i2s --s2i ppc_syscall > $@ gen_s390_tables_h_SOURCES = gen_tables.c gen_tables.h s390_table.h gen_s390_tables_h_CFLAGS = '-DTABLE_H="s390_table.h"' $(gen_s390_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_s390_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_s390_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_s390_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_s390_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_s390_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_s390_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_s390_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) s390_tables.h: gen_s390_tables_h Makefile ./gen_s390_tables_h --lowercase --i2s --s2i s390_syscall > $@ gen_s390x_tables_h_SOURCES = gen_tables.c gen_tables.h s390x_table.h gen_s390x_tables_h_CFLAGS = '-DTABLE_H="s390x_table.h"' $(gen_s390x_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_s390x_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_s390x_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_s390x_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_s390x_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_s390x_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_s390x_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_s390x_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) s390x_tables.h: gen_s390x_tables_h Makefile ./gen_s390x_tables_h --lowercase --i2s --s2i s390x_syscall > $@ gen_uringop_tables_h_SOURCES = gen_tables.c gen_tables.h uringop_table.h gen_uringop_tables_h_CFLAGS = '-DTABLE_H="uringop_table.h"' $(gen_uringop_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_uringop_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_uringop_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_uringop_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_uringop_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_uringop_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_uringop_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_uringop_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) uringop_tables.h: gen_uringop_tables_h Makefile ./gen_uringop_tables_h --lowercase --i2s --s2i uringop > $@ gen_x86_64_tables_h_SOURCES = gen_tables.c gen_tables.h x86_64_table.h gen_x86_64_tables_h_CFLAGS = '-DTABLE_H="x86_64_table.h"' $(gen_x86_64_tables_h_OBJECTS): CC=$(CC_FOR_BUILD) $(gen_x86_64_tables_h_OBJECTS): CFLAGS=$(CFLAGS_FOR_BUILD) $(gen_x86_64_tables_h_OBJECTS): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) $(gen_x86_64_tables_h_OBJECTS): LDFLAGS=$(LDFLAGS_FOR_BUILD) gen_x86_64_tables_h$(BUILD_EXEEXT): CC=$(CC_FOR_BUILD) gen_x86_64_tables_h$(BUILD_EXEEXT): CFLAGS=$(CFLAGS_FOR_BUILD) gen_x86_64_tables_h$(BUILD_EXEEXT): CPPFLAGS=$(CPPFLAGS_FOR_BUILD) gen_x86_64_tables_h$(BUILD_EXEEXT): LDFLAGS=$(LDFLAGS_FOR_BUILD) x86_64_tables.h: gen_x86_64_tables_h Makefile ./gen_x86_64_tables_h --lowercase --i2s --s2i x86_64_syscall > $@ audit-userspace-4.0.5/lib/aarch64_table.h000066400000000000000000000170241501761310600201400ustar00rootroot00000000000000/* aarch64_table.h -- * Copyright 2013-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(0, "io_setup") _S(1, "io_destroy") _S(2, "io_submit") _S(3, "io_cancel") _S(4, "io_getevents") _S(5, "setxattr") _S(6, "lsetxattr") _S(7, "fsetxattr") _S(8, "getxattr") _S(9, "lgetxattr") _S(10, "fgetxattr") _S(11, "listxattr") _S(12, "llistxattr") _S(13, "flistxattr") _S(14, "removexattr") _S(15, "lremovexattr") _S(16, "fremovexattr") _S(17, "getcwd") _S(18, "lookup_dcookie") _S(19, "eventfd2") _S(20, "epoll_create1") _S(21, "epoll_ctl") _S(22, "epoll_pwait") _S(23, "dup") _S(24, "dup3") _S(25, "fcntl") _S(26, "inotify_init1") _S(27, "inotify_add_watch") _S(28, "inotify_rm_watch") _S(29, "ioctl") _S(30, "ioprio_set") _S(31, "ioprio_get") _S(32, "flock") _S(33, "mknodat") _S(34, "mkdirat") _S(35, "unlinkat") _S(36, "symlinkat") _S(37, "linkat") _S(38, "renameat") _S(39, "umount2") _S(40, "mount") _S(41, "pivot_root") _S(42, "nfsservctl") _S(43, "statfs") _S(44, "fstatfs") _S(45, "truncate") _S(46, "ftruncate") _S(47, "fallocate") _S(48, "faccessat") _S(49, "chdir") _S(50, "fchdir") _S(51, "chroot") _S(52, "fchmod") _S(53, "fchmodat") _S(54, "fchownat") _S(55, "fchown") _S(56, "openat") _S(57, "close") _S(58, "vhangup") _S(59, "pipe2") _S(60, "quotactl") _S(61, "getdents") _S(62, "lseek") _S(63, "read") _S(64, "write") _S(65, "readv") _S(66, "writev") _S(67, "pread") _S(68, "pwrite") _S(69, "preadv") _S(70, "pwritev") _S(71, "sendfile") _S(72, "pselect6") _S(73, "ppoll") _S(74, "signalfd4") _S(75, "vmsplice") _S(76, "splice") _S(77, "tee") _S(78, "readlinkat") _S(79, "newfstatat") _S(80, "newfstat") _S(81, "sync") _S(82, "fsync") _S(83, "fdatasync") _S(84, "sync_file_range") _S(85, "timerfd_create") _S(86, "timerfd_settime") _S(87, "timerfd_gettime") _S(88, "utimensat") _S(89, "acct") _S(90, "capget") _S(91, "capset") _S(92, "personality") _S(93, "exit") _S(94, "exit_group") _S(95, "waitid") _S(96, "set_tid_address") _S(97, "unshare") _S(98, "futex") _S(99, "set_robust_list") _S(100, "get_robust_list") _S(101, "nanosleep") _S(102, "getitimer") _S(103, "setitimer") _S(104, "kexec_load") _S(105, "init_module") _S(106, "delete_module") _S(107, "timer_create") _S(108, "timer_gettime") _S(109, "timer_getoverrun") _S(110, "timer_settime") _S(111, "timer_delete") _S(112, "clock_settime") _S(113, "clock_gettime") _S(114, "clock_getres") _S(115, "clock_nanosleep") _S(116, "syslog") _S(117, "ptrace") _S(118, "sched_setparam") _S(119, "sched_setscheduler") _S(120, "sched_getscheduler") _S(121, "sched_getparam") _S(122, "sched_setaffinity") _S(123, "sched_getaffinity") _S(124, "sched_yield") _S(125, "sched_get_priority_max") _S(126, "sched_get_priority_min") _S(127, "sched_rr_get_interval") _S(128, "restart_syscall") _S(129, "kill") _S(130, "tkill") _S(131, "tgkill") _S(132, "sigaltstack") _S(133, "rt_sigsuspend") _S(134, "rt_sigaction") _S(135, "rt_sigprocmask") _S(136, "rt_sigpending") _S(137, "rt_sigtimedwait") _S(138, "rt_sigqueueinfo") _S(139, "rt_sigreturn") _S(140, "setpriority") _S(141, "getpriority") _S(142, "reboot") _S(143, "setregid") _S(144, "setgid") _S(145, "setreuid") _S(146, "setuid") _S(147, "setresuid") _S(148, "getresuid") _S(149, "setresgid") _S(150, "getresgid") _S(151, "setfsuid") _S(152, "setfsgid") _S(153, "times") _S(154, "setpgid") _S(155, "getpgid") _S(156, "getsid") _S(157, "setsid") _S(158, "getgroups") _S(159, "setgroups") _S(160, "uname") _S(161, "sethostname") _S(162, "setdomainname") _S(163, "getrlimit") _S(164, "setrlimit") _S(165, "getrusage") _S(166, "umask") _S(167, "prctl") _S(168, "getcpu") _S(169, "gettimeofday") _S(170, "settimeofday") _S(171, "adjtimex") _S(172, "getpid") _S(173, "getppid") _S(174, "getuid") _S(175, "geteuid") _S(176, "getgid") _S(177, "getegid") _S(178, "gettid") _S(179, "sysinfo") _S(180, "mq_open") _S(181, "mq_unlink") _S(182, "mq_timedsend") _S(183, "mq_timedreceive") _S(184, "mq_notify") _S(185, "mq_getsetattr") _S(186, "msgget") _S(187, "msgctl") _S(188, "msgrcv") _S(189, "msgsnd") _S(190, "semget") _S(191, "semctl") _S(192, "semtimedop") _S(193, "semop") _S(194, "shmget") _S(195, "shmctl") _S(196, "shmat") _S(197, "shmdt") _S(198, "socket") _S(199, "socketpair") _S(200, "bind") _S(201, "listen") _S(202, "accept") _S(203, "connect") _S(204, "getsockname") _S(205, "getpeername") _S(206, "sendto") _S(207, "recvfrom") _S(208, "setsockopt") _S(209, "getsockopt") _S(210, "shutdown") _S(211, "sendmsg") _S(212, "recvmsg") _S(213, "readahead") _S(214, "brk") _S(215, "munmap") _S(216, "mremap") _S(217, "add_key") _S(218, "request_key") _S(219, "keyctl") _S(220, "clone") _S(221, "execve") _S(222, "mmap") _S(223, "fadvise64") _S(224, "swapon") _S(225, "swapoff") _S(226, "mprotect") _S(227, "msync") _S(228, "mlock") _S(229, "munlock") _S(230, "mlockall") _S(231, "munlockall") _S(232, "mincore") _S(233, "madvise") _S(234, "remap_file_pages") _S(235, "mbind") _S(236, "get_mempolicy") _S(237, "set_mempolicy") _S(238, "migrate_pages") _S(239, "move_pages") _S(240, "rt_tgsigqueueinfo") _S(241, "perf_event_open") _S(242, "accept4") _S(243, "recvmmsg") _S(260, "wait4") _S(261, "prlimit64") _S(262, "fanotify_init") _S(263, "fanotify_mark") _S(264, "name_to_handle_at") _S(265, "open_by_handle_at") _S(266, "clock_adjtime") _S(267, "syncfs") _S(268, "setns") _S(269, "sendmmsg") _S(270, "process_vm_readv") _S(271, "process_vm_writev") _S(272, "kcmp") _S(273, "finit_module") _S(274, "sched_setattr") _S(275, "sched_getattr") _S(276, "renameat2") _S(277, "seccomp") _S(278, "getrandom") _S(279, "memfd_create") _S(280, "bpf") _S(281, "execveat") _S(282, "userfaultfd") _S(283, "membarrier") _S(284, "mlock2") _S(285, "copy_file_range") _S(286, "preadv2") _S(287, "pwritev2") _S(288, "pkey_mprotect") _S(289, "pkey_alloc") _S(290, "pkey_free") _S(291, "statx") _S(292, "io_pgetevents") _S(293, "rseq") _S(294, "kexec_file_load") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/actiontab.h000066400000000000000000000017461501761310600175110ustar00rootroot00000000000000/* actiontab.h -- * Copyright 2005,2006 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(AUDIT_NEVER, "never" ) _S(AUDIT_POSSIBLE, "possible" ) _S(AUDIT_ALWAYS, "always" ) audit-userspace-4.0.5/lib/arm_table.h000066400000000000000000000236751501761310600175000ustar00rootroot00000000000000/* arm_table.h -- * Copyright 2009-10,2013-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(0, "restart_syscall") _S(1, "exit") _S(2, "fork") _S(3, "read") _S(4, "write") _S(5, "open") _S(6, "close") _S(8, "creat") _S(9, "link") _S(10, "unlink") _S(11, "execve") _S(12, "chdir") _S(13, "time") _S(14, "mknod") _S(15, "chmod") _S(16, "lchown") _S(19, "lseek") _S(20, "getpid") _S(21, "mount") _S(22, "umount") _S(23, "setuid") _S(24, "getuid") _S(25, "stime") _S(26, "ptrace") _S(27, "alarm") _S(29, "pause") _S(30, "utime") _S(33, "access") _S(34, "nice") _S(36, "sync") _S(37, "kill") _S(38, "rename") _S(39, "mkdir") _S(40, "rmdir") _S(41, "dup") _S(42, "pipe") _S(43, "times") _S(45, "brk") _S(46, "setgid") _S(47, "getgid") _S(49, "geteuid") _S(50, "getegid") _S(51, "acct") _S(52, "umount2") _S(54, "ioctl") _S(55, "fcntl") _S(57, "setpgid") _S(60, "umask") _S(61, "chroot") _S(62, "ustat") _S(63, "dup2") _S(64, "getppid") _S(65, "getpgrp") _S(66, "setsid") _S(67, "sigaction") _S(70, "setreuid") _S(71, "setregid") _S(72, "sigsuspend") _S(73, "sigpending") _S(74, "sethostname") _S(75, "setrlimit") _S(76, "getrlimit") _S(77, "getrusage") _S(78, "gettimeofday") _S(79, "settimeofday") _S(80, "getgroups") _S(81, "setgroups") _S(82, "select") _S(83, "symlink") _S(85, "readlink") _S(86, "uselib") _S(87, "swapon") _S(88, "reboot") _S(89, "readdir") _S(90, "mmap") _S(91, "munmap") _S(92, "truncate") _S(93, "ftruncate") _S(94, "fchmod") _S(95, "fchown") _S(96, "getpriority") _S(97, "setpriority") _S(99, "statfs") _S(100, "fstatfs") _S(102, "socketcall") _S(103, "syslog") _S(104, "setitimer") _S(105, "getitimer") _S(106, "stat") _S(107, "lstat") _S(108, "fstat") _S(111, "vhangup") _S(113, "syscall") _S(114, "wait4") _S(115, "swapoff") _S(116, "sysinfo") _S(117, "ipc") _S(118, "fsync") _S(119, "sigreturn") _S(120, "clone") _S(121, "setdomainname") _S(122, "uname") _S(124, "adjtimex") _S(125, "mprotect") _S(126, "sigprocmask") _S(128, "init_module") _S(129, "delete_module") _S(131, "quotactl") _S(132, "getpgid") _S(133, "fchdir") _S(134, "bdflush") _S(135, "sysfs") _S(136, "personality") _S(138, "setfsuid") _S(139, "setfsgid") _S(140, "llseek") _S(141, "getdents") _S(142, "newselect") _S(143, "flock") _S(144, "msync") _S(145, "readv") _S(146, "writev") _S(147, "getsid") _S(148, "fdatasync") _S(149, "sysctl") _S(150, "mlock") _S(151, "munlock") _S(152, "mlockall") _S(153, "munlockall") _S(154, "sched_setparam") _S(155, "sched_getparam") _S(156, "sched_setscheduler") _S(157, "sched_getscheduler") _S(158, "sched_yield") _S(159, "sched_get_priority_max") _S(160, "sched_get_priority_min") _S(161, "sched_rr_get_interval") _S(162, "nanosleep") _S(163, "mremap") _S(164, "setresuid") _S(165, "getresuid") _S(168, "poll") _S(169, "nfsservctl") _S(170, "setresgid") _S(171, "getresgid") _S(172, "prctl") _S(173, "rt_sigreturn") _S(174, "rt_sigaction") _S(175, "rt_sigprocmask") _S(176, "rt_sigpending") _S(177, "rt_sigtimedwait") _S(178, "rt_sigqueueinfo") _S(179, "rt_sigsuspend") _S(180, "pread64") _S(181, "pwrite64") _S(182, "chown") _S(183, "getcwd") _S(184, "capget") _S(185, "capset") _S(186, "sigaltstack") _S(187, "sendfile") _S(190, "vfork") _S(191, "ugetrlimit") _S(192, "mmap2") _S(193, "truncate64") _S(194, "ftruncate64") _S(195, "stat64") _S(196, "lstat64") _S(197, "fstat64") _S(198, "lchown32") _S(199, "getuid32") _S(200, "getgid32") _S(201, "geteuid32") _S(202, "getegid32") _S(203, "setreuid32") _S(204, "setregid32") _S(205, "getgroups32") _S(206, "setgroups32") _S(207, "fchown32") _S(208, "setresuid32") _S(209, "getresuid32") _S(210, "setresgid32") _S(211, "getresgid32") _S(212, "chown32") _S(213, "setuid32") _S(214, "setgid32") _S(215, "setfsuid32") _S(216, "setfsgid32") _S(217, "getdents64") _S(218, "pivot_root") _S(219, "mincore") _S(220, "madvise") _S(221, "fcntl64") _S(224, "gettid") _S(225, "readahead") _S(226, "setxattr") _S(227, "lsetxattr") _S(228, "fsetxattr") _S(229, "getxattr") _S(230, "lgetxattr") _S(231, "fgetxattr") _S(232, "listxattr") _S(233, "llistxattr") _S(234, "flistxattr") _S(235, "removexattr") _S(236, "lremovexattr") _S(237, "fremovexattr") _S(238, "tkill") _S(239, "sendfile64") _S(240, "futex") _S(241, "sched_setaffinity") _S(242, "sched_getaffinity") _S(243, "io_setup") _S(244, "io_destroy") _S(245, "io_getevents") _S(246, "io_submit") _S(247, "io_cancel") _S(248, "exit_group") _S(249, "lookup_dcookie") _S(250, "epoll_create") _S(251, "epoll_ctl") _S(252, "epoll_wait") _S(253, "remap_file_pages") _S(256, "set_tid_address") _S(257, "timer_create") _S(258, "timer_settime") _S(259, "timer_gettime") _S(260, "timer_getoverrun") _S(261, "timer_delete") _S(262, "clock_settime") _S(263, "clock_gettime") _S(264, "clock_getres") _S(265, "clock_nanosleep") _S(266, "statfs64") _S(267, "fstatfs64") _S(268, "tgkill") _S(269, "utimes") // originally arm_fadvise64_64, but let's maintain common naming _S(270, "fadvise64_64") _S(271, "pciconfig_iobase") _S(272, "pciconfig_read") _S(273, "pciconfig_write") _S(274, "mq_open") _S(275, "mq_unlink") _S(276, "mq_timedsend") _S(277, "mq_timedreceive") _S(278, "mq_notify") _S(279, "mq_getsetattr") _S(280, "waitid") _S(281, "socket") _S(282, "bind") _S(283, "connect") _S(284, "listen") _S(285, "accept") _S(286, "getsockname") _S(287, "getpeername") _S(288, "socketpair") _S(289, "send") _S(290, "sendto") _S(291, "recv") _S(292, "recvfrom") _S(293, "shutdown") _S(294, "setsockopt") _S(295, "getsockopt") _S(296, "sendmsg") _S(297, "recvmsg") _S(298, "semop") _S(299, "semget") _S(300, "semctl") _S(301, "msgsnd") _S(302, "msgrcv") _S(303, "msgget") _S(304, "msgctl") _S(305, "shmat") _S(306, "shmdt") _S(307, "shmget") _S(308, "shmctl") _S(309, "add_key") _S(310, "request_key") _S(311, "keyctl") _S(312, "semtimedop") _S(313, "vserver") _S(314, "ioprio_set") _S(315, "ioprio_get") _S(316, "inotify_init") _S(317, "inotify_add_watch") _S(318, "inotify_rm_watch") _S(319, "mbind") _S(320, "get_mempolicy") _S(321, "set_mempolicy") _S(322, "openat") _S(323, "mkdirat") _S(324, "mknodat") _S(325, "fchownat") _S(326, "futimesat") _S(327, "fstatat64") _S(328, "unlinkat") _S(329, "renameat") _S(330, "linkat") _S(331, "symlinkat") _S(332, "readlinkat") _S(333, "fchmodat") _S(334, "faccessat") _S(335, "pselect6") _S(336, "ppoll") _S(337, "unshare") _S(338, "set_robust_list") _S(339, "get_robust_list") _S(340, "splice") // originally arm_sync_file_range, but let's maintain common naming _S(341, "sync_file_range") _S(342, "tee") _S(343, "vmsplice") _S(344, "move_pages") _S(345, "getcpu") _S(346, "epoll_pwait") _S(347, "kexec_load") _S(348, "utimensat") _S(349, "signalfd") _S(350, "timerfd_create") _S(351, "eventfd") _S(352, "fallocate") _S(353, "timerfd_settime") _S(354, "timerfd_gettime") _S(355, "signalfd4") _S(356, "eventfd2") _S(357, "epoll_create1") _S(358, "dup3") _S(359, "pipe2") _S(360, "inotify_init1") _S(361, "preadv") _S(362, "pwritev") _S(363, "rt_tgsigqueueinfo") _S(364, "perf_event_open") _S(365, "recvmmsg") _S(366, "accept4") _S(367, "fanotify_init") _S(368, "fanotify_mark") _S(369, "prlimit64") _S(370, "name_to_handle_at") _S(371, "open_by_handle_at") _S(372, "clock_adjtime") _S(373, "syncfs") _S(374, "sendmmsg") _S(375, "setns") _S(376, "process_vm_readv") _S(377, "process_vm_writev") _S(378, "kcmp") _S(379, "finit_module") _S(380, "sched_setattr") _S(381, "sched_getattr") _S(382, "renameat2") _S(383, "seccomp") _S(384, "getrandom") _S(385, "memfd_create") _S(386, "bpf") _S(387, "execveat") _S(388, "userfaultfd") _S(389, "membarrier") _S(390, "mlock2") _S(391, "copy_file_range") _S(392, "preadv2") _S(393, "pwritev2") _S(394, "pkey_mprotect") _S(395, "pkey_alloc") _S(396, "pkey_free") _S(397, "statx") _S(398, "rseq") _S(399, "io_pgetevents") _S(400, "migrate_pages") _S(401, "kexec_file_load") _S(403, "clock_gettime64") _S(404, "clock_settime64") _S(405, "clock_adjtime64") _S(406, "clock_getres_time64") _S(407, "clock_nanosleep_time64") _S(408, "timer_gettime64") _S(409, "timer_settime64") _S(410, "timerfd_gettime64") _S(411, "timerfd_settime64") _S(412, "utimensat_time64") _S(413, "pselect6_time64") _S(414, "ppoll_time64") _S(416, "io_pgetevents_time64") _S(417, "recvmmsg_time64") _S(418, "mq_timedsend_time64") _S(419, "mq_timedreceive_time64") _S(420, "semtimedop_time64") _S(421, "rt_sigtimedwait_time64") _S(422, "futex_time64") _S(423, "sched_rr_get_interval64") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/audit-fgets.c000066400000000000000000000106761501761310600177560ustar00rootroot00000000000000/* audit-fgets.c -- a replacement for glibc's fgets * Copyright 2018,2022,2025 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include "libaudit.h" /* * The theory of operation for this family of functions is that it * operates like the glibc fgets function except with a descriptor. * It reads from the descriptor into a buffer and then looks through * the buffer to find a string terminated with a '\n'. It terminates * the string with a 0 and returns it. It updates current to point * to where it left off. On the next read it starts there and tries to * find a '\n'. If it can't find one, it slides the buffer down and * fills as much as it can from the descriptor. If the descriptor * becomes invalid or there is an error reading, it makes eof true. * The variable eptr marks the end of the buffer. It never changes. */ #define BUF_SIZE 8192 static char buffer[2*BUF_SIZE+1] = { 0 }; static char *current = buffer; static char *const eptr = buffer+(2*BUF_SIZE); static int eof = 0; int audit_fgets_eof(void) { return eof; } /* This function dumps any accumulated text. This is to remove dangling text * that never got consumed for the intended purpose. */ void audit_fgets_clear(void) { buffer[0] = 0; current = buffer; eof = 0; } /* Function to check if we have more data stored * and ready to process. If we have a newline or enough * bytes we return 1 for success. Otherwise 0 meaning that * there is not enough to process without blocking. */ int audit_fgets_more(size_t blen) { size_t avail; char *nl; assert(blen != 0); avail = current - buffer; /* only scan the valid region */ nl = memchr(buffer, '\n', avail); return (nl || avail >= blen - 1); } /* Function to read the next chunk of data from the given fd. If we have * data to return, we Read up to blen-1 chars (or through the next newline), * copy into buf, NUL-terminate, and return the number of chars. * It also returns 0 for no data. And -1 if there was an error reading * the fd. */ int audit_fgets(char *buf, size_t blen, int fd) { size_t avail = current - buffer, line_len; char *line_end; ssize_t nread; assert(blen != 0); /* 1) Is there already a '\n' in the buffered data? */ line_end = memchr(buffer, '\n', avail); /* 2) If not, and we still can read more, pull in more data */ if (line_end == NULL && !eof && current != eptr) { do { nread = read(fd, current, eptr - current); } while (nread < 0 && errno == EINTR); if (nread < 0) return -1; if (nread == 0) eof = 1; else { current[nread] = '\0'; current += nread; avail += nread; } /* see if a newline arrived in that chunk */ line_end = memchr(buffer, '\n', avail); } /* 3) Do we now have enough to return? */ if (line_end == NULL) { /* not a full line—only return early if we still expect more */ if (!eof && avail < blen - 1 && current != eptr) return 0; /* else we’ll return whatever we have (either at EOF, * buffer‑full, or enough for blen) */ } /* 4) Compute how many chars to hand back */ if (line_end) { /* include the '\n', but never exceed blen-1 */ line_len = (line_end - buffer) + 1; if (line_len > blen - 1) line_len = blen - 1; } else /* no newline: return up to blen-1 or whatever’s left * at EOF/full */ line_len = (avail < blen - 1) ? avail : (blen - 1); /* 5) Copy out, slide the remainder down, reset pointers */ memcpy(buf, buffer, line_len); buf[line_len] = '\0'; size_t remainder = avail - line_len; if (remainder > 0) memmove(buffer, buffer + line_len, remainder); current = buffer + remainder; *current = '\0'; return (int)line_len; } audit-userspace-4.0.5/lib/audit-records.h000066400000000000000000000327321501761310600203110ustar00rootroot00000000000000/* audit-records.h -- * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef _AUDIT_RECORDS_H #define _AUDIT_RECORDS_H #include #ifdef __cplusplus extern "C" { #endif /* Audit message types as of 5.0 kernel: * 1000 - 1099 are for commanding the audit system * 1100 - 1199 user space trusted application messages * 1200 - 1299 messages internal to the audit daemon * 1300 - 1399 audit event messages * 1400 - 1499 kernel SE Linux use * 1500 - 1599 AppArmor events * 1600 - 1699 kernel crypto events * 1700 - 1799 kernel anomaly records * 1800 - 1899 kernel integrity labels and related events * 1800 - 1999 future kernel use * 2001 - 2099 unused (kernel) * 2100 - 2199 user space anomaly records * 2200 - 2299 user space actions taken in response to anomalies * 2300 - 2399 user space generated LSPP events * 2400 - 2499 user space crypto events * 2500 - 2599 user space virtualization management events * 2600 - 2999 future user space (maybe integrity labels and related events) */ #define AUDIT_FIRST_USER_MSG 1100 /* First user space message */ #define AUDIT_LAST_USER_MSG 1199 /* Last user space message */ #define AUDIT_USER_AUTH 1100 /* User system access authentication */ #define AUDIT_USER_ACCT 1101 /* User system access authorization */ #define AUDIT_USER_MGMT 1102 /* User acct attribute change */ #define AUDIT_CRED_ACQ 1103 /* User credential acquired */ #define AUDIT_CRED_DISP 1104 /* User credential disposed */ #define AUDIT_USER_START 1105 /* User session start */ #define AUDIT_USER_END 1106 /* User session end */ #define AUDIT_USER_AVC 1107 /* User space avc message */ #define AUDIT_USER_CHAUTHTOK 1108 /* User acct password or pin changed */ #define AUDIT_USER_ERR 1109 /* User acct state error */ #define AUDIT_CRED_REFR 1110 /* User credential refreshed */ #define AUDIT_USYS_CONFIG 1111 /* User space system config change */ #define AUDIT_USER_LOGIN 1112 /* User has logged in */ #define AUDIT_USER_LOGOUT 1113 /* User has logged out */ #define AUDIT_ADD_USER 1114 /* User account added */ #define AUDIT_DEL_USER 1115 /* User account deleted */ #define AUDIT_ADD_GROUP 1116 /* Group account added */ #define AUDIT_DEL_GROUP 1117 /* Group account deleted */ #define AUDIT_DAC_CHECK 1118 /* User space DAC check results */ #define AUDIT_CHGRP_ID 1119 /* User space group ID changed */ #define AUDIT_TEST 1120 /* Used for test success messages */ #define AUDIT_TRUSTED_APP 1121 /* Trusted app msg - freestyle text */ #define AUDIT_USER_SELINUX_ERR 1122 /* SE Linux user space error */ #define AUDIT_USER_CMD 1123 /* User shell command and args */ #define AUDIT_USER_TTY 1124 /* Non-ICANON TTY input meaning */ #define AUDIT_CHUSER_ID 1125 /* Changed user ID supplemental data */ #define AUDIT_GRP_AUTH 1126 /* Authentication for group password */ #define AUDIT_SYSTEM_BOOT 1127 /* System boot */ #define AUDIT_SYSTEM_SHUTDOWN 1128 /* System shutdown */ #define AUDIT_SYSTEM_RUNLEVEL 1129 /* System runlevel change */ #define AUDIT_SERVICE_START 1130 /* Service (daemon) start */ #define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ #define AUDIT_GRP_MGMT 1132 /* Group account attr was modified */ #define AUDIT_GRP_CHAUTHTOK 1133 /* Group acct password or pin changed */ #define AUDIT_MAC_CHECK 1134 /* User space MAC decision results */ #define AUDIT_ACCT_LOCK 1135 /* User's account locked by admin */ #define AUDIT_ACCT_UNLOCK 1136 /* User's account unlocked by admin */ #define AUDIT_USER_DEVICE 1137 /* User space hotplug device changes */ #define AUDIT_SOFTWARE_UPDATE 1138 /* Software update event */ #define AUDIT_FIRST_DAEMON 1200 #define AUDIT_LAST_DAEMON 1299 #define AUDIT_DAEMON_RECONFIG 1204 /* Auditd should reconfigure */ #define AUDIT_DAEMON_ROTATE 1205 /* Auditd should rotate logs */ #define AUDIT_DAEMON_RESUME 1206 /* Auditd should resume logging */ #define AUDIT_DAEMON_ACCEPT 1207 /* Auditd accepted remote connection */ #define AUDIT_DAEMON_CLOSE 1208 /* Auditd closed remote connection */ #define AUDIT_DAEMON_ERR 1209 /* Auditd internal error */ #define AUDIT_FIRST_EVENT 1300 #define AUDIT_LAST_EVENT 1399 #define AUDIT_FIRST_SELINUX 1400 #define AUDIT_LAST_SELINUX 1499 #define AUDIT_FIRST_APPARMOR 1500 #define AUDIT_LAST_APPARMOR 1599 #ifndef AUDIT_AA #define AUDIT_AA 1500 /* Not upstream yet */ #define AUDIT_APPARMOR_AUDIT 1501 #define AUDIT_APPARMOR_ALLOWED 1502 #define AUDIT_APPARMOR_DENIED 1503 #define AUDIT_APPARMOR_HINT 1504 #define AUDIT_APPARMOR_STATUS 1505 #define AUDIT_APPARMOR_ERROR 1506 #define AUDIT_APPARMOR_KILL 1507 #endif #define AUDIT_FIRST_KERN_CRYPTO_MSG 1600 #define AUDIT_LAST_KERN_CRYPTO_MSG 1699 #define AUDIT_FIRST_KERN_ANOM_MSG 1700 #define AUDIT_LAST_KERN_ANOM_MSG 1799 #define AUDIT_INTEGRITY_FIRST_MSG 1800 #define AUDIT_INTEGRITY_LAST_MSG 1899 #ifndef AUDIT_INTEGRITY_DATA #define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */ #define AUDIT_INTEGRITY_METADATA 1801 // Metadata integrity verification #define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */ #define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */ #define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */ #define AUDIT_INTEGRITY_RULE 1805 /* Policy rule */ #endif #ifndef AUDIT_INTEGRITY_EVM_XATTR #define AUDIT_INTEGRITY_EVM_XATTR 1806 /* New EVM-covered xattr */ #endif #ifndef AUDIT_INTEGRITY_POLICY_RULE #define AUDIT_INTEGRITY_POLICY_RULE 1807 /* Integrity Policy rule */ #endif #define AUDIT_FIRST_ANOM_MSG 2100 #define AUDIT_LAST_ANOM_MSG 2199 #define AUDIT_ANOM_LOGIN_FAILURES 2100 // Failed login limit reached #define AUDIT_ANOM_LOGIN_TIME 2101 // Login attempted at bad time #define AUDIT_ANOM_LOGIN_SESSIONS 2102 // Max concurrent sessions reached #define AUDIT_ANOM_LOGIN_ACCT 2103 // Login attempted to watched acct #define AUDIT_ANOM_LOGIN_LOCATION 2104 // Login from forbidden location #define AUDIT_ANOM_MAX_DAC 2105 // Max DAC failures reached #define AUDIT_ANOM_MAX_MAC 2106 // Max MAC failures reached #define AUDIT_ANOM_AMTU_FAIL 2107 // AMTU failure #define AUDIT_ANOM_RBAC_FAIL 2108 // RBAC self test failure #define AUDIT_ANOM_RBAC_INTEGRITY_FAIL 2109 // RBAC file integrity failure #define AUDIT_ANOM_CRYPTO_FAIL 2110 // Crypto system test failure #define AUDIT_ANOM_ACCESS_FS 2111 // Access of file or dir #define AUDIT_ANOM_EXEC 2112 // Execution of file #define AUDIT_ANOM_MK_EXEC 2113 // Make an executable #define AUDIT_ANOM_ADD_ACCT 2114 // Adding an acct #define AUDIT_ANOM_DEL_ACCT 2115 // Deleting an acct #define AUDIT_ANOM_MOD_ACCT 2116 // Changing an acct #define AUDIT_ANOM_ROOT_TRANS 2117 // User became root #define AUDIT_ANOM_LOGIN_SERVICE 2118 // Service acct attempted login #define AUDIT_ANOM_LOGIN_ROOT 2119 // Root login attempted #define AUDIT_ANOM_ORIGIN_FAILURES 2120 // Origin has too many failed login #define AUDIT_ANOM_SESSION 2121 // The user session is bad #define AUDIT_FIRST_ANOM_RESP 2200 #define AUDIT_LAST_ANOM_RESP 2299 #define AUDIT_RESP_ANOMALY 2200 /* Anomaly not reacted to */ #define AUDIT_RESP_ALERT 2201 /* Alert email was sent */ #define AUDIT_RESP_KILL_PROC 2202 /* Kill program */ #define AUDIT_RESP_TERM_ACCESS 2203 /* Terminate session */ #define AUDIT_RESP_ACCT_REMOTE 2204 /* Acct locked from remote access*/ #define AUDIT_RESP_ACCT_LOCK_TIMED 2205 /* User acct locked for time */ #define AUDIT_RESP_ACCT_UNLOCK_TIMED 2206 /* User acct unlocked from time */ #define AUDIT_RESP_ACCT_LOCK 2207 /* User acct was locked */ #define AUDIT_RESP_TERM_LOCK 2208 /* Terminal was locked */ #define AUDIT_RESP_SEBOOL 2209 /* Set an SE Linux boolean */ #define AUDIT_RESP_EXEC 2210 /* Execute a script */ #define AUDIT_RESP_SINGLE 2211 /* Go to single user mode */ #define AUDIT_RESP_HALT 2212 /* take the system down */ #define AUDIT_RESP_ORIGIN_BLOCK 2213 /* Address blocked by iptables */ #define AUDIT_RESP_ORIGIN_BLOCK_TIMED 2214 /* Address blocked for time */ #define AUDIT_RESP_ORIGIN_UNBLOCK_TIMED 2215 /* Address unblocked from timed */ #define AUDIT_FIRST_USER_LSPP_MSG 2300 #define AUDIT_LAST_USER_LSPP_MSG 2399 #define AUDIT_USER_ROLE_CHANGE 2300 /* User changed to a new role */ #define AUDIT_ROLE_ASSIGN 2301 /* Admin assigned user to role */ #define AUDIT_ROLE_REMOVE 2302 /* Admin removed user from role */ #define AUDIT_LABEL_OVERRIDE 2303 /* Admin is overriding a label */ #define AUDIT_LABEL_LEVEL_CHANGE 2304 /* Object's level was changed */ #define AUDIT_USER_LABELED_EXPORT 2305 /* Object exported with label */ #define AUDIT_USER_UNLABELED_EXPORT 2306 /* Object exported without label */ #define AUDIT_DEV_ALLOC 2307 /* Device was allocated */ #define AUDIT_DEV_DEALLOC 2308 /* Device was deallocated */ #define AUDIT_FS_RELABEL 2309 /* Filesystem relabeled */ #define AUDIT_USER_MAC_POLICY_LOAD 2310 /* Userspc daemon loaded policy */ #define AUDIT_ROLE_MODIFY 2311 /* Admin modified a role */ #define AUDIT_USER_MAC_CONFIG_CHANGE 2312 /* Change made to MAC policy */ #define AUDIT_USER_MAC_STATUS 2313 /* Userspc daemon enforcing change */ #define AUDIT_FIRST_CRYPTO_MSG 2400 #define AUDIT_CRYPTO_TEST_USER 2400 /* Crypto test results */ #define AUDIT_CRYPTO_PARAM_CHANGE_USER 2401 /* Crypto attribute change */ #define AUDIT_CRYPTO_LOGIN 2402 /* Logged in as crypto officer */ #define AUDIT_CRYPTO_LOGOUT 2403 /* Logged out from crypto */ #define AUDIT_CRYPTO_KEY_USER 2404 /* Create,delete,negotiate */ #define AUDIT_CRYPTO_FAILURE_USER 2405 /* Fail decrypt,encrypt,randomiz */ #define AUDIT_CRYPTO_REPLAY_USER 2406 /* Crypto replay detected */ #define AUDIT_CRYPTO_SESSION 2407 /* Record parameters set during TLS session establishment */ #define AUDIT_CRYPTO_IKE_SA 2408 /* Record parameters related to IKE SA */ #define AUDIT_CRYPTO_IPSEC_SA 2409 /* Record parameters related to IPSEC SA */ #define AUDIT_LAST_CRYPTO_MSG 2499 /* Events for both VMs and container orchestration software */ #define AUDIT_FIRST_VIRT_MSG 2500 #define AUDIT_VIRT_CONTROL 2500 /* Start,Pause,Stop VM/container */ #define AUDIT_VIRT_RESOURCE 2501 /* Resource assignment */ #define AUDIT_VIRT_MACHINE_ID 2502 /* Binding of label to VM/cont */ #define AUDIT_VIRT_INTEGRITY_CHECK 2503 /* Guest integrity results */ #define AUDIT_VIRT_CREATE 2504 /* Creation of guest image */ #define AUDIT_VIRT_DESTROY 2505 /* Destruction of guest image */ #define AUDIT_VIRT_MIGRATE_IN 2506 /* Inbound guest migration info */ #define AUDIT_VIRT_MIGRATE_OUT 2507 /* Outbound guest migration info */ #define AUDIT_LAST_VIRT_MSG 2599 #ifndef AUDIT_FIRST_USER_MSG2 #define AUDIT_FIRST_USER_MSG2 2100 /* More userspace messages */ #define AUDIT_LAST_USER_MSG2 2999 #endif /* New kernel event definitions since 5.0 */ #ifndef AUDIT_BPF #define AUDIT_BPF 1334 /* BPF load/unload */ #endif #ifndef AUDIT_EVENT_LISTENER #define AUDIT_EVENT_LISTENER 1335 /* audit mcast sock join/part */ #endif #ifndef AUDIT_URINGOP #define AUDIT_URINGOP 1336 /* io_uring operations */ #endif #ifndef AUDIT_OPENAT2 #define AUDIT_OPENAT2 1337 /* openat2 open_how flags */ #endif #ifndef AUDIT_DM_CTRL #define AUDIT_DM_CTRL 1338 /* Device Mapper target control */ #endif #ifndef AUDIT_DM_EVENT #define AUDIT_DM_EVENT 1339 /* Device Mapper events */ #endif #ifndef AUDIT_ANOM_CREAT #define AUDIT_ANOM_CREAT 1703 /* Suspicious file creation */ #endif #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/lib/audit.pc.in000066400000000000000000000004541501761310600174260ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: libaudit Description: Libraries needed for apps that use the kernel audit framework Version: @VERSION@ Libs: -L${libdir} -laudit Libs.private: @CAPNG_LDADD@ Cflags: -I${includedir} Requires.private: @CAPNG_PKG@ audit-userspace-4.0.5/lib/audit_logging.c000066400000000000000000000517741501761310600203620ustar00rootroot00000000000000/* audit_logging.c -- * Copyright 2005-2008,2010,2011,2013,2017 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include // inet6 addrlen #include // gethostbyname #include // inet_ntop #include #include // PATH_MAX #include #include "libaudit.h" #include "private.h" #define TTY_PATH 32 #define MAX_USER ((UT_NAMESIZE * 2) + 8) // NOTE: The kernel fills in pid, uid, and loginuid of sender. Therefore, // these routines do not need to send them. /* * resolve's the hostname - caller must pass a INET6_ADDRSTRLEN byte buffer * Returns string w/ numerical address, or "?" on failure */ static void _resolve_addr(char buf[], const char *host) { struct addrinfo *ai; struct addrinfo hints; int e; buf[0] = '?'; buf[1] = 0; /* Short circuit this lookup if NULL, or empty */ if (host == NULL || *host == 0) return; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; e = getaddrinfo(host, NULL, &hints, &ai); if (e != 0) { audit_msg(LOG_ERR, "resolve_addr: cannot resolve hostname %s (%s)", host, gai_strerror(e)); return; } // What to do if more than 1 addr? inet_ntop(ai->ai_family, ai->ai_family == AF_INET ? (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr : (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, buf, INET6_ADDRSTRLEN); freeaddrinfo(ai); } /* * This function checks a string to see if it needs encoding. It * return 1 if needed and 0 if not */ int audit_value_needs_encoding(const char *str, unsigned int size) { unsigned int i; if (str == NULL) return 0; for (i=0; i 0x7f because str[] is signed. if (str[i] == '"' || str[i] < 0x21 || str[i] == 0x7F) return 1; } return 0; } /* * This function does encoding of "untrusted" names just like the kernel */ char *audit_encode_value(char *final, const char *buf, unsigned int size) { unsigned int i; char *ptr = final; const char *hex = "0123456789ABCDEF"; if (final == NULL) return NULL; if (buf == NULL) { *final = 0; return final; } for (i=0; i>4]; /* Upper nibble */ *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */ } *ptr = 0; return final; } char *audit_encode_nv_string(const char *name, const char *value, unsigned int vlen) { char *str; if (vlen == 0 && value) vlen = strlen(value); if (value && audit_value_needs_encoding(value, vlen)) { char *tmp = malloc(2*vlen + 1); if (tmp) { audit_encode_value(tmp, value, vlen); if (asprintf(&str, "%s=%s", name, tmp) < 0) str = NULL; free(tmp); } else str = NULL; } else if (asprintf(&str, "%s=\"%s\"", name, value ? value : "?") < 0) str = NULL; return str; } /* * Get the executable's name */ static char *_get_exename(char *exename, int size) { int res; char tmp[PATH_MAX+1]; /* get the name of the current executable */ if ((res = readlink("/proc/self/exe", tmp, PATH_MAX)) == -1) { strcpy(exename, "\"?\""); audit_msg(LOG_ERR, "get_exename: cannot determine executable"); } else { tmp[res] = '\0'; if (audit_value_needs_encoding(tmp, res)) return audit_encode_value(exename, tmp, res); snprintf(exename, size, "\"%s\"", tmp); } return exename; } /* * Get the command line name * NOTE: at the moment, this only escapes what the user sent */ static char *_get_commname(const char *comm, char *commname, unsigned int size) { unsigned int len; char tmp_comm[20]; if (comm == NULL) { ssize_t ret; int fd = open("/proc/self/comm", O_RDONLY|O_CLOEXEC); if (fd < 0) { strcpy(commname, "\"?\""); return commname; } ret = read(fd, tmp_comm, sizeof(tmp_comm)); close(fd); if (ret > 0) tmp_comm[ret-1] = 0; else { strcpy(commname, "\"?\""); return commname; } comm = tmp_comm; } len = strlen(comm); if (audit_value_needs_encoding(comm, len)) audit_encode_value(commname, comm, len); else snprintf(commname, size, "\"%s\"", comm); return commname; } static int check_ttyname(const char *ttyn) { struct stat statbuf; if (lstat(ttyn, &statbuf) || !S_ISCHR(statbuf.st_mode) || (statbuf.st_nlink > 1 && strncmp(ttyn, "/dev/", 5))) { audit_msg(LOG_ERR, "FATAL: bad tty %s", ttyn); return 1; } return 0; } static const char *_get_tty(char *tname, int size) { int rc, i, found = 0; for (i=0; i<3 && !found; i++) { rc = ttyname_r(i, tname, size); if (rc == 0 && tname[0] != '\0') found = 1; } if (!found) return NULL; if (check_ttyname(tname)) return NULL; if (strncmp(tname, "/dev/", 5) == 0) return &tname[5]; return tname; } #define HOSTLEN 64 static char _host[HOSTLEN] = ""; static const char *_get_hostname(const char *ttyn) { if (ttyn && ((strncmp(ttyn, "pts", 3) == 0) || (strncmp(ttyn, "tty", 3) == 0) || (strncmp(ttyn, "/dev/tty", 8) == 0) || (strncmp(ttyn, "/dev/pts", 8) == 0) )) { if (_host[0] == 0) { gethostname(_host, HOSTLEN); _host[HOSTLEN - 1] = 0; } return _host; } return NULL; } /* * This function will log a message to the audit system using a predefined * message format. This function should be used by all console apps that do * not manipulate accounts or groups. * * audit_fd - The fd returned by audit_open * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN * message - the message being sent * hostname - the hostname if known * addr - The network address of the user * tty - The tty of the user * result - 1 is "success" and 0 is "failed" * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_user_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, int result) { char buf[MAX_AUDIT_MESSAGE_LENGTH]; char addrbuf[INET6_ADDRSTRLEN]; static char exename[PATH_MAX*2]=""; char ttyname[TTY_PATH]; const char *success; int ret; if (audit_fd < 0) return 0; if (result) success = "success"; else success = "failed"; /* If hostname is empty string, make it NULL ptr */ if (hostname && *hostname == 0) hostname = NULL; /* See if we can deduce addr */ addrbuf[0] = 0; if (addr == NULL || strlen(addr) == 0) _resolve_addr(addrbuf, hostname); else strncat(addrbuf, addr, sizeof(addrbuf)-1); /* Fill in exec name if needed */ if (exename[0] == 0) _get_exename(exename, sizeof(exename)); /* Fill in tty if needed */ if (tty == NULL) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; /* Get the local name if we have a real tty */ if (hostname == NULL && tty) hostname = _get_hostname(tty); snprintf(buf, sizeof(buf), "%s exe=%s hostname=%s addr=%s terminal=%s res=%s", message, exename, hostname ? hostname : "?", addrbuf, tty ? tty : "?", success ); errno = 0; ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf ); if ((ret < 1) && errno == 0) errno = ret; return ret; } /* * This function will log a message to the audit system using a predefined * message format. This function should be used by all console apps that do * not manipulate accounts or groups and are executing a script. An example * would be python or crond wanting to say what they are executing. * * audit_fd - The fd returned by audit_open * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN * message - the message being sent * comm - the program command line name * hostname - the hostname if known * addr - The network address of the user * tty - The tty of the user * result - 1 is "success" and 0 is "failed" * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_user_comm_message(int audit_fd, int type, const char *message, const char *comm, const char *hostname, const char *addr, const char *tty, int result) { char buf[MAX_AUDIT_MESSAGE_LENGTH]; char addrbuf[INET6_ADDRSTRLEN]; static char exename[PATH_MAX*2]=""; char commname[PATH_MAX*2]; char ttyname[TTY_PATH]; const char *success; int ret; if (audit_fd < 0) return 0; if (result) success = "success"; else success = "failed"; /* If hostname is empty string, make it NULL ptr */ if (hostname && *hostname == 0) hostname = NULL; /* See if we can deduce addr */ addrbuf[0] = 0; if (addr == NULL || strlen(addr) == 0) _resolve_addr(addrbuf, hostname); else strncat(addrbuf, addr, sizeof(addrbuf)-1); /* Fill in exec name if needed */ if (exename[0] == 0) _get_exename(exename, sizeof(exename)); /* Fill in tty if needed */ if (tty == NULL) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; _get_commname(comm, commname, sizeof(commname)); /* Get the local name if we have a real tty */ if (hostname == NULL && tty) hostname = _get_hostname(tty); snprintf(buf, sizeof(buf), "%s comm=%s exe=%s hostname=%s addr=%s terminal=%s res=%s", message, commname, exename, hostname ? hostname : "?", addrbuf, tty ? tty : "?", success ); errno = 0; ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf ); if ((ret < 1) && errno == 0) errno = ret; return ret; } /* * This function will log a message to the audit system using a predefined * message format. It should be used for all account manipulation operations. * Parameter usage is as follows: * * audit_fd - The fd returned by audit_open * type - type of message: AUDIT_USER_CHAUTHTOK for changing any account * attributes. * pgname - program's name * op - operation. "adding user", "changing finger info", "deleting group" * name - user's account or group name. If not available use NULL. * id - uid or gid that the operation is being performed on. This is used * only when user is NULL. * host - The hostname if known * addr - The network address of the user * tty - The tty of the user * result - 1 is "success" and 0 is "failed" * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_acct_message(int audit_fd, int type, const char *pgname, const char *op, const char *name, unsigned int id, const char *host, const char *addr, const char *tty, int result) { const char *success; char buf[MAX_AUDIT_MESSAGE_LENGTH]; char addrbuf[INET6_ADDRSTRLEN]; static char exename[PATH_MAX*2] = ""; char ttyname[TTY_PATH]; int ret; if (audit_fd < 0) return 0; if (result) success = "success"; else success = "failed"; /* If hostname is empty string, make it NULL ptr */ if (host && *host == 0) host = NULL; /* See if we can deduce addr */ addrbuf[0] = 0; if (addr == NULL || strlen(addr) == 0) _resolve_addr(addrbuf, host); else strncat(addrbuf, addr, sizeof(addrbuf)-1); /* Fill in exec name if needed */ if (pgname == NULL) { if (exename[0] == 0) _get_exename(exename, sizeof(exename)); } else if (pgname[0] != '"') snprintf(exename, sizeof(exename), "\"%s\"", pgname); else snprintf(exename, sizeof(exename), "%s", pgname); /* Fill in tty if needed */ if (tty == NULL) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; /* Get the local name if we have a real tty */ if (host == NULL && tty) host = _get_hostname(tty); if (name && id == (unsigned int)-1) { char user[MAX_USER]; int encoded = 0; size_t len; user[0] = 0; strncat(user, name, MAX_USER-1); len = strnlen(user, UT_NAMESIZE); user[len] = 0; if (audit_value_needs_encoding(name, len)) { audit_encode_value(user, name, len); encoded = 1; } snprintf(buf, sizeof(buf), encoded ? "op=%s acct=%s exe=%s hostname=%s addr=%s terminal=%s res=%s" : "op=%s acct=\"%s\" exe=%s hostname=%s addr=%s terminal=%s res=%s", op, user, exename, host ? host : "?", addrbuf, tty ? tty : "?", success ); } else snprintf(buf, sizeof(buf), "op=%s id=%u exe=%s hostname=%s addr=%s terminal=%s res=%s", op, id, exename, host ? host : "?", addrbuf, tty ? tty : "?", success ); errno = 0; ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf); if ((ret < 1) && errno == 0) errno = ret; return ret; } /* * This function will log a message to the audit system using a predefined * message format. This function should be used by all apps that are SE Linux * object managers. * * audit_fd - The fd returned by audit_open * type - type of message, ex: AUDIT_USER, AUDIT_USYS_CONFIG, AUDIT_USER_LOGIN * message - the message being sent * hostname - the hostname if known * addr - The network address of the user * tty - The tty of the user * auid - The auid of the person related to the avc message * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_user_avc_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, uid_t auid) { char buf[MAX_AUDIT_MESSAGE_LENGTH]; char addrbuf[INET6_ADDRSTRLEN]; static char exename[PATH_MAX*2] = ""; char ttyname[TTY_PATH]; int retval; if (audit_fd < 0) return 0; /* If hostname is empty string, make it NULL ptr */ if (hostname && *hostname == 0) hostname = NULL; addrbuf[0] = 0; if (addr == NULL || strlen(addr) == 0) _resolve_addr(addrbuf, hostname); else strncat(addrbuf, addr, sizeof(addrbuf)-1); if (exename[0] == 0) _get_exename(exename, sizeof(exename)); if (tty == NULL) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; snprintf(buf, sizeof(buf), "%s exe=%s sauid=%d hostname=%s addr=%s terminal=%s", message, exename, auid, hostname ? hostname : "?", addrbuf, tty ? tty : "?" ); errno = 0; retval = audit_send_user_message( audit_fd, type, REAL_ERR, buf ); if (retval == -EPERM && !audit_can_write()) { syslog(LOG_ERR, "Can't send to audit system: %s %s", audit_msg_type_to_name(type), buf); return 0; } if ((retval < 1) && errno == 0) errno = retval; return retval; } /* * This function will log a message to the audit system using a predefined * message format. It should be used for all SE linux user and role * manipulation operations. * Parameter usage is as follows: * * type - type of message: AUDIT_ROLE_ASSIGN/REMOVE for changing any SE Linux * user or role attributes. * pgname - program's name * op - operation. "adding-user", "adding-role", "deleting-user", "deleting-role" * name - user's account. If not available use NULL. * id - uid that the operation is being performed on. This is used * only when name is NULL. * new_seuser - the new seuser that the login user is getting * new_role - the new_role that the login user is getting * new_range - the new mls range that the login user is getting * old_seuser - the old seuser that the login usr had * old_role - the old role that the login user had * old_range - the old mls range that the login usr had * host - The hostname if known * addr - The network address of the user * tty - The tty of the user * result - 1 is "success" and 0 is "failed" * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_semanage_message(int audit_fd, int type, const char *pgname, const char *op, const char *name, unsigned int id, const char *new_seuser, const char *new_role, const char *new_range, const char *old_seuser, const char *old_role, const char *old_range, const char *host, const char *addr, const char *tty, int result) { const char *success; char buf[MAX_AUDIT_MESSAGE_LENGTH]; char addrbuf[INET6_ADDRSTRLEN]; static char exename[PATH_MAX*2] = ""; char ttyname[TTY_PATH]; int ret; if (audit_fd < 0) return 0; if (result) success = "success"; else success = "failed"; /* If hostname is empty string, make it NULL ptr */ if (host && *host == 0) host = NULL; addrbuf[0] = 0; if (addr == NULL || strlen(addr) == 0) _resolve_addr(addrbuf, host); else strncat(addrbuf, addr, sizeof(addrbuf)-1); if (pgname == NULL || strlen(pgname) == 0) { if (exename[0] == 0) _get_exename(exename, sizeof(exename)); pgname = exename; } if (tty == NULL || strlen(tty) == 0) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; if (name && strlen(name) > 0) { size_t len; int encoded = 0; char user[MAX_USER]; user[0] = 0; strncat(user, name, MAX_USER-1); len = strnlen(user, UT_NAMESIZE); user[len] = 0; if (audit_value_needs_encoding(name, len)) { audit_encode_value(user, name, len); encoded = 1; } snprintf(buf, sizeof(buf), encoded ? "op=%s acct=%s old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s" : "op=%s acct=\"%s\" old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s", op, user, old_seuser && strlen(old_seuser) ? old_seuser : "?", old_role && strlen(old_role) ? old_role : "?", old_range && strlen(old_range) ? old_range : "?", new_seuser && strlen(new_seuser) ? new_seuser : "?", new_role && strlen(new_role) ? new_role : "?", new_range && strlen(new_range) ? new_range : "?", pgname, host && strlen(host) ? host : "?", addrbuf, tty && strlen(tty) ? tty : "?", success ); } else snprintf(buf, sizeof(buf), "op=%s id=%u old-seuser=%s old-role=%s old-range=%s new-seuser=%s new-role=%s new-range=%s exe=%s hostname=%s addr=%s terminal=%s res=%s", op, id, old_seuser && strlen(old_seuser) ? old_seuser : "?", old_role && strlen(old_role) ? old_role : "?", old_range && strlen(old_range) ? old_range : "?", new_seuser && strlen(new_seuser) ? new_seuser : "?", new_role && strlen(new_role) ? new_role : "?", new_range && strlen(new_range) ? new_range : "?", pgname, host && strlen(host) ? host : "?", addrbuf, tty && strlen(tty) ? tty : "?", success ); errno = 0; ret = audit_send_user_message(audit_fd, type, REAL_ERR, buf); if ((ret < 1) && errno == 0) errno = ret; return ret; } /* * This function will log a message to the audit system using a predefined * message format. This function should be used by all console apps that do * not manipulate accounts or groups. * * audit_fd - The fd returned by audit_open * type - type of message, ex: AUDIT_USER_CMD * command - the command line being logged * tty - The tty of the user * result - 1 is "success" and 0 is "failed" * * It returns the sequence number which is > 0 on success or <= 0 on error. */ int audit_log_user_command(int audit_fd, int type, const char *command, const char *tty, int result) { char *p; char buf[MAX_AUDIT_MESSAGE_LENGTH]; char commname[PATH_MAX*2]; char cwdname[PATH_MAX*2]; char ttyname[TTY_PATH]; static char exename[PATH_MAX*2] = ""; char format[64]; const char *success; char *cmd; int ret, cwdenc=0, cmdenc=0; unsigned int len; if (audit_fd < 0) return 0; if (result) success = "success"; else success = "failed"; if (tty == NULL) tty = _get_tty(ttyname, TTY_PATH); else if (*tty == 0) tty = NULL; if (exename[0] == 0) _get_exename(exename, sizeof(exename)); /* Trim leading spaces */ while (*command == ' ') command++; cmd = strdup(command); if (cmd == NULL) return -1; // We borrow the commname buffer if (getcwd(commname, PATH_MAX) == NULL) strcpy(commname, "?"); len = strlen(commname); if (audit_value_needs_encoding(commname, len)) { audit_encode_value(cwdname, commname, len); cwdenc = 1; } else strcpy(cwdname, commname); len = strlen(cmd); // Trim the trailing carriage return and spaces while (len && (cmd[len-1] == 0x0A || cmd[len-1] == ' ')) { cmd[len-1] = 0; len--; } if (len >= PATH_MAX) { cmd[PATH_MAX] = 0; len = PATH_MAX-1; } if (audit_value_needs_encoding(cmd, len)) { audit_encode_value(commname, cmd, len); cmdenc = 1; } if (cmdenc == 0) strcpy(commname, cmd); free(cmd); // Make the format string if (cwdenc) p=stpcpy(format, "cwd=%s "); else p=stpcpy(format, "cwd=\"%s\" "); if (cmdenc) p = stpcpy(p, "cmd=%s "); else p = stpcpy(p, "cmd=\"%s\" "); strcpy(p, "exe=%s terminal=%s res=%s"); // now use the format string to make the event snprintf(buf, sizeof(buf), format, cwdname, commname, exename, tty ? tty : "?", success ); errno = 0; ret = audit_send_user_message( audit_fd, type, HIDE_IT, buf ); if ((ret < 1) && errno == 0) errno = ret; return ret; } audit-userspace-4.0.5/lib/audit_logging.h000066400000000000000000000061251501761310600203550ustar00rootroot00000000000000/* audit_logging.h -- * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef _AUDIT_LOGGING_H #define _AUDIT_LOGGING_H // Next include is to pick up the function attribute macros #include #include #ifdef __cplusplus extern "C" { #endif // The following macros originate in sys/cdefs.h // gcc-analyzer notation // Define buffer access modes #ifndef __attr_access # define __attr_access(x) #endif #ifndef __attr_dealloc # define __attr_dealloc(dealloc, argno) # define __attr_dealloc_free #endif // Warn unused result #ifndef __wur # define __wur #endif /* Prerequisite to logging is acquiring and disposing of netlink connections */ int audit_open(void) __wur; void audit_close(int fd); /* The following are for standard formatting of messages */ int audit_value_needs_encoding(const char *str, unsigned int size) __attr_access ((__read_only__, 1, 2)) __wur; char *audit_encode_value(char *final,const char *buf,unsigned int size) __attr_access ((__write_only__, 1)) __attr_access ((__read_only__, 2, 3)); char *audit_encode_nv_string(const char *name, const char *value, unsigned int vlen) __attr_access ((__read_only__, 2, 3)) __attr_dealloc_free; int audit_log_user_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, int result) __wur; int audit_log_user_comm_message(int audit_fd, int type, const char *message, const char *comm, const char *hostname, const char *addr, const char *tty, int result) __wur; int audit_log_acct_message(int audit_fd, int type, const char *pgname, const char *op, const char *name, unsigned int id, const char *host, const char *addr, const char *tty, int result) __wur; int audit_log_user_avc_message(int audit_fd, int type, const char *message, const char *hostname, const char *addr, const char *tty, uid_t auid); int audit_log_semanage_message(int audit_fd, int type, const char *pgname, const char *op, const char *name, unsigned int id, const char *new_seuser, const char *new_role, const char *new_range, const char *old_seuser, const char *old_role, const char *old_range, const char *host, const char *addr, const char *tty, int result); int audit_log_user_command(int audit_fd, int type, const char *command, const char *tty, int result) __wur; #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/lib/deprecated.c000066400000000000000000000050261501761310600176330ustar00rootroot00000000000000/* deprecated.c -- This file is the trash heap of things about to leave * Copyright 2006-07,2009,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include "libaudit.h" #include "private.h" /* * This function will send a user space message to the kernel. * It returns the sequence number which is > 0 on success * or <= 0 on error. (pam uses this) This is the main audit sending * function now. */ int audit_send_user_message(int fd, int type, hide_t hide_error, const char *message) { int retry_cnt = 0; int rc; retry: rc = audit_send(fd, type, message, strlen(message)+1); if (rc == -ECONNREFUSED) { /* This is here to let people that build their own kernel and disable the audit system get in. ECONNREFUSED is issued by the kernel when there is "no on listening". */ return 0; } else if (rc == -EPERM && !audit_can_write() && hide_error == HIDE_IT) { /* If we get this, then the kernel supports auditing * but we don't have enough privilege to write to the * socket. Therefore, we have already been authenticated * and we are a common user. Just act as though auditing * is not enabled. Any other error we take seriously. * This is here basically to satisfy Xscreensaver. */ return 0; } else if (rc == -EINVAL) { /* If we get this, the kernel doesn't understand the * netlink message type. This is most likely due to * being an old kernel. Use the old message type. */ if (type >= AUDIT_FIRST_USER_MSG && type <= AUDIT_LAST_USER_MSG && !retry_cnt) { /* do retry */ type = AUDIT_USER; retry_cnt++; goto retry; } } return rc; } audit-userspace-4.0.5/lib/dso.h000066400000000000000000000023371501761310600163270ustar00rootroot00000000000000/* dso.h -- * Copyright 2005,2006,2009 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef _DSO_H_ #define _DSO_H_ /* * This is to mark functions as internal to the API */ #ifndef AUDIT_HIDDEN_START #define AUDIT_HIDDEN_START _Pragma("GCC visibility push(hidden)") #endif /* * This ends the section that is internal to the API. */ #ifndef AUDIT_HIDDEN_END #define AUDIT_HIDDEN_END _Pragma("GCC visibility pop") #endif #endif audit-userspace-4.0.5/lib/errormsg.h000066400000000000000000000116211501761310600173760ustar00rootroot00000000000000/* errormsg.h -- * Copyright 2008 FUJITSU Inc. * Copyright 2012-17,2020 Red Hat * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Zhang Xiliang * Steve Grubb * Richard Guy Briggs */ struct msg_tab { int key; /* error number */ /* * the field string position in the error message * 0: don't output field string * 1: output field string before error message * 2: output field string after error message * 3: print nothing */ int position; const char *cvalue; }; #ifndef NO_TABLES #define EAU_OPMISSING 1 #define EAU_FIELDUNKNOWN 2 #define EAU_ARCHMISPLACED 3 #define EAU_ARCHUNKNOWN 4 #define EAU_ELFUNKNOWN 5 #define EAU_ARCHNOBIT 6 #define EAU_EXITONLY 7 #define EAU_MSGTYPEUNKNOWN 8 #define EAU_MSGTYPEEXCLUDEUSER 9 #define EAU_UPGRADEFAIL 10 #define EAU_STRTOOLONG 11 #define EAU_MSGTYPECREDEXCLUDE 12 #define EAU_OPEQNOTEQ 13 #define EAU_PERMRWXA 14 #define EAU_ERRUNKNOWN 15 #define EAU_FILETYPEUNKNOWN 16 #define EAU_EXITENTRYONLY 17 #define EAU_KEYDEP 19 #define EAU_FIELDVALMISSING 20 #define EAU_FIELDVALNUM 21 #define EAU_FIELDNAME 22 #define EAU_COMPFIELDNAME 24 #define EAU_COMPVAL 25 #define EAU_COMPFIELDUNKNOWN 26 #define EAU_COMPVALUNKNOWN 27 #define EAU_FIELDTOOMANY 28 #define EAU_OPEQ 29 #define EAU_FIELDNOSUPPORT 30 #define EAU_FIELDNOFILTER 31 #define EAU_FILTERMISSING 32 #define EAU_COMPINCOMPAT 33 #define EAU_FIELDUNAVAIL 34 #define EAU_FILTERNOSUPPORT 35 #define EAU_FSTYPEUNKNOWN 36 #define EAU_FIELDVALTOOBIG 37 #define EAU_PRINT_NOTHING 38 #define EAU_PERM_SYSCALL 39 static const struct msg_tab err_msgtab[] = { { -EAU_OPMISSING, 2, "-F missing operation for" }, { -EAU_FIELDUNKNOWN, 2, "-F unknown field:" }, { -EAU_ARCHMISPLACED, 1, "must be before -S" }, { -EAU_ARCHUNKNOWN, 1, "machine type not found" }, { -EAU_ELFUNKNOWN, 1, "elf mapping not found" }, { -EAU_ARCHNOBIT, 1, "requested bit level not supported by machine" }, { -EAU_EXITONLY, 1, "can only be used with exit filter list" }, { -EAU_MSGTYPEUNKNOWN, 2, "-F unknown message type -" }, { -EAU_MSGTYPEEXCLUDEUSER, 0, "msgtype field can only be used with exclude or user filter list" }, { -EAU_UPGRADEFAIL, 0, "Failed upgrading rule" }, { -EAU_STRTOOLONG, 0, "String value too long" }, { -EAU_MSGTYPECREDEXCLUDE, 0, "Only msgtype, *uid, *gid, pid, and subj* fields can be used with exclude filter" }, { -EAU_OPEQNOTEQ, 1, "only takes = or != operators" }, { -EAU_PERMRWXA, 0, "Permission can only contain \'rwxa\'" }, { -EAU_ERRUNKNOWN, 2, "-F unknown errno -"}, { -EAU_FILETYPEUNKNOWN, 2, "-F unknown file type - " }, { -EAU_EXITENTRYONLY, 1, "can only be used with exit and entry filter list" }, { -18, 1, "" }, // Deprecated don't reuse { -EAU_KEYDEP, 0, "Key field needs a watch, syscall or exe path given prior to it" }, { -EAU_FIELDVALMISSING, 2, "-F missing value after operation for" }, { -EAU_FIELDVALNUM, 2, "-F value should be number for" }, { -EAU_FIELDNAME, 2, "-F missing field name before operator for" }, { -23, 2, "" }, // Deprecated don't reuse { -EAU_COMPFIELDNAME, 2, "-C missing field name before operator for" }, { -EAU_COMPVAL, 2, "-C missing value after operation for "}, { -EAU_COMPFIELDUNKNOWN, 2, "-C unknown field:" }, { -EAU_COMPVALUNKNOWN, 2, "-C unknown right hand value for comparison with:" }, { -EAU_FIELDTOOMANY, 2, "Too many fields in rule:" }, { -EAU_OPEQ, 1, "only takes = operator" }, { -EAU_FIELDNOSUPPORT, 2, "Field option not supported by kernel:" }, { -EAU_FIELDNOFILTER, 1, "must be used with exclude, user, or exit filter" }, { -EAU_FILTERMISSING, 0, "filter is missing from rule" }, { -EAU_COMPINCOMPAT, 2, "-C incompatible comparison" }, { -EAU_FIELDUNAVAIL, 1, "field is not valid for the filter" }, { -EAU_FILTERNOSUPPORT, 1, "filter is not supported by the kernel" }, { -EAU_FSTYPEUNKNOWN, 2, "file system type is unknown for field:" }, { -EAU_FIELDVALTOOBIG, 2, "value is too large for field:" }, { -EAU_PRINT_NOTHING, 3, "" }, { -EAU_PERM_SYSCALL, 0, "Error adding syscalls for perm filtering" }, }; #endif audit-userspace-4.0.5/lib/errtab.h000066400000000000000000000110511501761310600170120ustar00rootroot00000000000000/* errtab.h -- * Copyright 2007,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Locations: /usr/include/asm-generic/errno-base.h * /usr/include/asm-generic/errno.h */ _S(EPERM, "EPERM" ) // start of errno-base.h _S(ENOENT, "ENOENT" ) _S(ESRCH, "ESRCH" ) _S(EINTR, "EINTR" ) _S(EIO, "EIO" ) _S(ENXIO, "ENXIO" ) _S(E2BIG, "E2BIG" ) _S(ENOEXEC, "ENOEXEC" ) _S(EBADF, "EBADF" ) _S(ECHILD, "ECHILD" ) _S(EAGAIN, "EAGAIN" ) _S(ENOMEM, "ENOMEM" ) _S(EACCES, "EACCES" ) _S(EFAULT, "EFAULT" ) _S(ENOTBLK, "ENOTBLK" ) _S(EBUSY, "EBUSY" ) _S(EEXIST, "EEXIST" ) _S(EXDEV, "EXDEV" ) _S(ENODEV, "ENODEV" ) _S(ENOTDIR, "ENOTDIR" ) _S(EISDIR, "EISDIR" ) _S(EINVAL, "EINVAL" ) _S(ENFILE, "ENFILE" ) _S(EMFILE, "EMFILE" ) _S(ENOTTY, "ENOTTY" ) _S(ETXTBSY, "ETXTBSY" ) _S(EFBIG, "EFBIG" ) _S(ENOSPC, "ENOSPC" ) _S(ESPIPE, "ESPIPE" ) _S(EROFS, "EROFS" ) _S(EMLINK, "EMLINK" ) _S(EPIPE, "EPIPE" ) _S(EDOM, "EDOM" ) _S(ERANGE, "ERANGE" ) _S(EDEADLK, "EDEADLK" ) // start asm-generic/errno.h _S(ENAMETOOLONG, "ENAMETOOLONG" ) _S(ENOLCK, "ENOLCK" ) _S(ENOSYS, "ENOSYS" ) _S(ENOTEMPTY, "ENOTEMPTY" ) _S(ELOOP, "ELOOP" ) _S(EWOULDBLOCK, "EWOULDBLOCK" ) _S(ENOMSG, "ENOMSG" ) _S(EIDRM, "EIDRM" ) _S(ECHRNG, "ECHRNG" ) _S(EL2NSYNC, "EL2NSYNC" ) _S(EL3HLT, "EL3HLT" ) _S(EL3RST, "EL3RST" ) _S(ELNRNG, "ELNRNG" ) _S(EUNATCH, "EUNATCH" ) _S(ENOCSI, "ENOCSI" ) _S(EL2HLT, "EL2HLT" ) _S(EBADE, "EBADE" ) _S(EBADR, "EBADR" ) _S(EXFULL, "EXFULL" ) _S(ENOANO, "ENOANO" ) _S(EBADRQC, "EBADRQC" ) _S(EBADSLT, "EBADSLT" ) _S(EDEADLOCK, "EDEADLOCK" ) _S(EBFONT, "EBFONT" ) _S(ENOSTR, "ENOSTR" ) _S(ENODATA, "ENODATA" ) _S(ETIME, "ETIME" ) _S(ENOSR, "ENOSR" ) _S(ENONET, "ENONET" ) _S(ENOPKG, "ENOPKG" ) _S(EREMOTE, "EREMOTE" ) _S(ENOLINK, "ENOLINK" ) _S(EADV, "EADV" ) _S(ESRMNT, "ESRMNT" ) _S(ECOMM, "ECOMM" ) _S(EPROTO, "EPROTO" ) _S(EMULTIHOP, "EMULTIHOP" ) _S(EDOTDOT, "EDOTDOT" ) _S(EBADMSG, "EBADMSG" ) _S(EOVERFLOW, "EOVERFLOW" ) _S(ENOTUNIQ, "ENOTUNIQ" ) _S(EBADFD, "EBADFD" ) _S(EREMCHG, "EREMCHG" ) _S(ELIBACC, "ELIBACC" ) _S(ELIBBAD, "ELIBBAD" ) _S(ELIBSCN, "ELIBSCN" ) _S(ELIBMAX, "ELIBMAX" ) _S(ELIBEXEC, "ELIBEXEC" ) _S(EILSEQ, "EILSEQ" ) _S(ERESTART, "ERESTART" ) _S(ESTRPIPE, "ESTRPIPE" ) _S(EUSERS, "EUSERS" ) _S(ENOTSOCK, "ENOTSOCK" ) _S(EDESTADDRREQ, "EDESTADDRREQ" ) _S(EMSGSIZE, "EMSGSIZE" ) _S(EPROTOTYPE, "EPROTOTYPE" ) _S(ENOPROTOOPT, "ENOPROTOOPT" ) _S(EPROTONOSUPPORT, "EPROTONOSUPPORT" ) _S(ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT" ) _S(EOPNOTSUPP, "EOPNOTSUPP" ) _S(EPFNOSUPPORT, "EPFNOSUPPORT" ) _S(EAFNOSUPPORT, "EAFNOSUPPORT" ) _S(EADDRINUSE, "EADDRINUSE" ) _S(EADDRNOTAVAIL, "EADDRNOTAVAIL" ) _S(ENETDOWN, "ENETDOWN" ) _S(ENETUNREACH, "ENETUNREACH" ) _S(ENETRESET, "ENETRESET" ) _S(ECONNABORTED, "ECONNABORTED" ) _S(ECONNRESET, "ECONNRESET" ) _S(ENOBUFS, "ENOBUFS" ) _S(EISCONN, "EISCONN" ) _S(ENOTCONN, "ENOTCONN" ) _S(ESHUTDOWN, "ESHUTDOWN" ) _S(ETOOMANYREFS, "ETOOMANYREFS" ) _S(ETIMEDOUT, "ETIMEDOUT" ) _S(ECONNREFUSED, "ECONNREFUSED" ) _S(EHOSTDOWN, "EHOSTDOWN" ) _S(EHOSTUNREACH, "EHOSTUNREACH" ) _S(EALREADY, "EALREADY" ) _S(EINPROGRESS, "EINPROGRESS" ) _S(ESTALE, "ESTALE" ) _S(EUCLEAN, "EUCLEAN" ) _S(ENOTNAM, "ENOTNAM" ) _S(ENAVAIL, "ENAVAIL" ) _S(EISNAM, "EISNAM" ) _S(EREMOTEIO, "EREMOTEIO" ) _S(EDQUOT, "EDQUOT" ) _S(ENOMEDIUM, "ENOMEDIUM" ) _S(EMEDIUMTYPE, "EMEDIUMTYPE" ) _S(ECANCELED, "ECANCELED" ) _S(ENOKEY, "ENOKEY" ) _S(EKEYEXPIRED, "EKEYEXPIRED" ) _S(EKEYREVOKED, "EKEYREVOKED" ) _S(EKEYREJECTED, "EKEYREJECTED" ) _S(EOWNERDEAD, "EOWNERDEAD" ) _S(ENOTRECOVERABLE, "ENOTRECOVERABLE" ) _S(ERFKILL, "ERFKILL" ) _S(EHWPOISON, "EHWPOISON" ) audit-userspace-4.0.5/lib/fieldtab.h000066400000000000000000000053541501761310600173160ustar00rootroot00000000000000/* fieldtab.h -- * Copyright 2005-07,2015-16 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Richard Guy Briggs */ _S(AUDIT_PID, "pid" ) _S(AUDIT_UID, "uid" ) _S(AUDIT_EUID, "euid" ) _S(AUDIT_SUID, "suid" ) _S(AUDIT_FSUID, "fsuid" ) _S(AUDIT_GID, "gid" ) _S(AUDIT_EGID, "egid" ) _S(AUDIT_SGID, "sgid" ) _S(AUDIT_FSGID, "fsgid" ) _S(AUDIT_LOGINUID, "auid" ) _S(AUDIT_LOGINUID, "loginuid" ) _S(AUDIT_PERS, "pers" ) _S(AUDIT_ARCH, "arch" ) _S(AUDIT_MSGTYPE, "msgtype" ) _S(AUDIT_SUBJ_USER, "subj_user" ) _S(AUDIT_SUBJ_ROLE, "subj_role" ) _S(AUDIT_SUBJ_TYPE, "subj_type" ) _S(AUDIT_SUBJ_SEN, "subj_sen" ) _S(AUDIT_SUBJ_CLR, "subj_clr" ) _S(AUDIT_PPID, "ppid" ) _S(AUDIT_OBJ_USER, "obj_user" ) _S(AUDIT_OBJ_ROLE, "obj_role" ) _S(AUDIT_OBJ_TYPE, "obj_type" ) _S(AUDIT_OBJ_LEV_LOW, "obj_lev_low" ) _S(AUDIT_OBJ_LEV_HIGH, "obj_lev_high" ) _S(AUDIT_SESSIONID, "sessionid" ) _S(AUDIT_DEVMAJOR, "devmajor" ) _S(AUDIT_DEVMINOR, "devminor" ) _S(AUDIT_INODE, "inode" ) _S(AUDIT_EXIT, "exit" ) _S(AUDIT_SUCCESS, "success" ) _S(AUDIT_WATCH, "path" ) _S(AUDIT_PERM, "perm" ) _S(AUDIT_DIR, "dir" ) _S(AUDIT_FILETYPE, "filetype" ) _S(AUDIT_FSTYPE, "fstype" ) _S(AUDIT_OBJ_UID, "obj_uid" ) _S(AUDIT_OBJ_GID, "obj_gid" ) _S(AUDIT_FIELD_COMPARE, "field_compare" ) _S(AUDIT_ARG0, "a0" ) _S(AUDIT_ARG1, "a1" ) _S(AUDIT_ARG2, "a2" ) _S(AUDIT_ARG3, "a3" ) _S(AUDIT_FILTERKEY, "key" ) _S(AUDIT_EXE, "exe" ) _S(AUDIT_SADDR_FAM, "saddr_fam" ) audit-userspace-4.0.5/lib/flagtab.h000066400000000000000000000023161501761310600171370ustar00rootroot00000000000000/* flagtab.h -- * Copyright 2005,2006,2016,2022 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Richard Guy Briggs */ #include "config.h" _S(AUDIT_FILTER_TASK, "task" ) _S(AUDIT_FILTER_EXIT, "exit" ) _S(AUDIT_FILTER_USER, "user" ) _S(AUDIT_FILTER_EXCLUDE, "exclude" ) _S(AUDIT_FILTER_FS, "filesystem") #ifdef WITH_IO_URING _S(AUDIT_FILTER_URING_EXIT, "io_uring" ) #endif audit-userspace-4.0.5/lib/fstypetab.h000066400000000000000000000017521501761310600175430ustar00rootroot00000000000000/* fstypetab.h -- * Copyright 2017 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * * Source of info: /usr/include/linux/magic.h * */ _S(0x74726163, "tracefs" ) _S(0x64626720, "debugfs" ) audit-userspace-4.0.5/lib/ftypetab.h000066400000000000000000000021151501761310600173520ustar00rootroot00000000000000/* actiontab.h -- * Copyright 2008 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(S_IFSOCK, "socket" ) _S(S_IFLNK, "link" ) _S(S_IFREG, "file" ) _S(S_IFBLK, "block" ) _S(S_IFDIR, "dir" ) _S(S_IFCHR, "character" ) _S(S_IFIFO, "fifo" ) audit-userspace-4.0.5/lib/gen_tables.c000066400000000000000000000273011501761310600176360ustar00rootroot00000000000000/* gen_tables.c -- Generator of lookup tables. * Copyright 2008 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MS_DIRSYNC #include #endif #include "gen_tables.h" #include "libaudit.h" #include "auparse-defs.h" /* This is from asm/ipc.h. Copying it for now as some platforms * * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 #define DIPC 25 /* * Defines EHWPOISON to the value found in uapi/asm-generic/errno.h, * which is correct for most (but not all architectures). */ #ifndef EHWPOISON #define EHWPOISON 133 #endif /* The ratio of table size to number of non-empty elements allowed for a "direct" s2i table; if the ratio would be bigger, bsearch tables are used instead. 2 looks like a lot at a first glance, but the bsearch tables need twice as much space per element, so with the ratio equal to 2 the direct table uses no more memory and is faster. */ #define DIRECT_THRESHOLD 2 /* Allow more than one string defined for a single integer value */ static bool allow_duplicate_ints; /* = false; */ struct value { int val; const char *s; size_t s_offset; size_t orig_index; }; /* The mapping to store. */ static struct value values[] = { #define _S(VAL, S) { (VAL), (S), 0, 0 }, #include TABLE_H #undef _S }; #define NUM_VALUES (sizeof(values) / sizeof(*values)) /* Compare two "struct value" members by name. */ static int cmp_value_strings(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; return strcmp(a->s, b->s); } /* Compare two "struct value" members by value. */ static int cmp_value_vals(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->val > b->val) return 1; if (a->val < b->val) return -1; /* Preserve the original order if there is an ambiguity, to always use the first specified value. */ if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Compare two "struct value" members by orig_index. */ static int cmp_value_orig_index(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Output the string table, initialize values[*]->s_offset. */ static void output_strings(const char *prefix) { size_t i, offset; offset = 0; for (i = 0; i < NUM_VALUES; i++) { values[i].s_offset = offset; offset += strlen(values[i].s) + 1; } printf("static const char %s_strings[] = \"", prefix); assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES; i++) { const char *c; if (i != 0 && i % 10 == 0) fputs("\"\n" "\t\"", stdout); for (c = values[i].s; *c != '\0'; c++) { assert(*c != '"' && *c != '\\' && isprint((unsigned char)*c)); putc(*c, stdout); } if (i != NUM_VALUES - 1) fputs("\\0", stdout); } fputs("\";\n", stdout); } /* Output the string to integer mapping code. Assume strings are all uppsercase or all lowercase if specified by parameters; in that case, make the search case-insensitive. values must be sorted by strings. */ static void output_s2i(const char *prefix, bool uppercase, bool lowercase) { size_t i; for (i = 0; i < NUM_VALUES - 1; i++) { assert(strcmp(values[i].s, values[i + 1].s) <= 0); if (strcmp(values[i].s, values[i + 1].s) == 0) { fprintf(stderr, "Duplicate value `%s': %d, %d\n", values[i].s, values[i].val, values[i + 1].val); abort(); } } printf("static const unsigned %s_s2i_s[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(values[i].s_offset <= UINT_MAX); printf("%zu,", values[i].s_offset); } printf("\n" "};\n" "static const int %s_s2i_i[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%d,", values[i].val); } fputs("\n" "};\n", stdout); assert(!(uppercase && lowercase)); if (uppercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISLOWER(*c)); } } else if (lowercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISUPPER(*c)); } } if (uppercase || lowercase) { printf("static int %s_s2i(const char *s, int *value) {\n" "\tsize_t len, i;\n" "\t if (s == NULL || value == NULL)\n" "\t\treturn 0;\n" "\tlen = strlen(s);\n" "\t{ char copy[len + 1];\n" "\tfor (i = 0; i < len; i++) {\n" "\t\tchar c = s[i];\n", prefix); if (uppercase) fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' " ": c;\n", stdout); else fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' " ": c;\n", stdout); printf("\t}\n" "\tcopy[i] = 0;\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, " "copy, value);\n" "\t}\n" "}\n", prefix, prefix, prefix, NUM_VALUES); } else printf("static int %s_s2i(const char *s, int *value) {\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, " "value);\n" "}\n", prefix, prefix, prefix, prefix, NUM_VALUES); } /* Output the string to integer mapping table. values must be sorted by strings. */ static void output_i2s(const char *prefix) { struct value *unique_values; int min_val, max_val; size_t i, n; assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES - 1; i++) { assert(values[i].val <= values[i + 1].val); if (!allow_duplicate_ints && values[i].val == values[i + 1].val) { fprintf(stderr, "Duplicate value %d: `%s', `%s'\n", values[i].val, values[i].s, values[i + 1].s); abort(); } } unique_values = malloc(NUM_VALUES * sizeof(*unique_values)); if (unique_values == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } n = 0; for (i = 0; i < NUM_VALUES; i++) { if (n == 0 || unique_values[n - 1].val != values[i].val) { unique_values[n] = values[i]; n++; } } min_val = unique_values[0].val; max_val = unique_values[n - 1].val; if (((double)max_val - (double)min_val) / n <= DIRECT_THRESHOLD) { int next_index; printf("static const unsigned %s_i2s_direct[] = {", prefix); next_index = min_val; i = 0; for (;;) { if ((next_index - min_val) % 10 == 0) fputs("\n\t", stdout); while (unique_values[i].val < next_index) /* This can happen if (allow_duplicate_ints) */ i++; if (unique_values[i].val == next_index) { assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } else fputs("-1u,", stdout); if (next_index == max_val) /* Done like this to avoid integer overflow */ break; next_index++; } printf("\n" "};\n" "static const char *%s_i2s(int v) {\n" "\treturn i2s_direct__(%s_strings, %s_i2s_direct, %d, " "%d, v);\n" "}\n", prefix, prefix, prefix, min_val, max_val); } else { printf("static const int %s_i2s_i[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%d,", unique_values[i].val); } printf("\n" "};\n" "static const unsigned %s_i2s_s[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } printf("\n" "};\n" "static const char *%s_i2s(int v) {\n" "\treturn i2s_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, " "%zu, v);\n" "}\n", prefix, prefix, prefix, prefix, n); } free(unique_values); } /* Output the string to integer mapping table as a transtab[]. values must be sorted in the desired order. */ static void output_i2s_transtab(const char *prefix) { size_t i; char *uc_prefix; printf("static const struct transtab %s_table[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("{%d,%zu},", values[i].val, values[i].s_offset); } uc_prefix = strdup(prefix); if (uc_prefix == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } for (i = 0; uc_prefix[i] != '\0'; i++) uc_prefix[i] = toupper((unsigned char)uc_prefix[i]); printf("\n" "};\n" "#define %s_NUM_ENTRIES " "(sizeof(%s_table) / sizeof(*%s_table))\n", uc_prefix, prefix, prefix); free(uc_prefix); } int main(int argc, char **argv) { bool gen_i2s, gen_i2s_transtab, gen_s2i, uppercase, lowercase; char *prefix; size_t i; /* This is required by gen_tables.h */ assert(NUM_VALUES <= (SSIZE_MAX / 2 + 1)); /* To make sure GT_ISUPPER and GT_ISLOWER work. */ assert('Z' == 'A' + 25 && 'z' == 'a' + 25); gen_i2s = false; gen_i2s_transtab = false; gen_s2i = false; uppercase = false; lowercase = false; prefix = NULL; assert (argc > 1); for (i = 1; i < (size_t)argc; i++) { if (strcmp(argv[i], "--i2s") == 0) gen_i2s = true; else if (strcmp(argv[i], "--i2s-transtab") == 0) gen_i2s_transtab = true; else if (strcmp(argv[i], "--s2i") == 0) gen_s2i = true; else if (strcmp(argv[i], "--uppercase") == 0) uppercase = true; else if (strcmp(argv[i], "--lowercase") == 0) lowercase = true; else if (strcmp(argv[i], "--duplicate-ints") == 0) allow_duplicate_ints = true; else { assert(*argv[i] != '-'); assert(prefix == NULL); prefix = argv[i]; } } assert(prefix != NULL); assert(!(uppercase && lowercase)); printf("/* This is a generated file, see Makefile.am for its " "inputs. */\n"); for (i = 0; i < NUM_VALUES; i++) values[i].orig_index = i; qsort(values, NUM_VALUES, sizeof(*values), cmp_value_strings); /* FIXME? if (gen_s2i), sort the strings in some other order (e.g. "first 4 nodes in BFS of the bsearch tree first") to use the cache better. */ /* FIXME? If the only thing generated is a transtab, keep the strings in the original order to use the cache better. */ output_strings(prefix); if (gen_s2i) output_s2i(prefix, uppercase, lowercase); if (gen_i2s) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_vals); output_i2s(prefix); } if (gen_i2s_transtab) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_orig_index); output_i2s_transtab(prefix); } return EXIT_SUCCESS; } audit-userspace-4.0.5/lib/gen_tables.h000066400000000000000000000046741501761310600176530ustar00rootroot00000000000000/* gen_tables.h -- Declarations used for lookup tables. * Copyright 2008 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač */ #ifndef GEN_TABLES_H__ #define GEN_TABLES_H__ #include #include /* Assumes ASCII; verified in gen_tables.c. */ #define GT_ISUPPER(X) ((X) >= 'A' && (X) <= 'Z') #define GT_ISLOWER(X) ((X) >= 'a' && (X) <= 'z') inline static int s2i__(const char *strings, const unsigned *s_table, const int *i_table, size_t n, const char *s, int *value) { ssize_t left, right; left = 0; right = n - 1; while (left <= right) { /* invariant: left <= x <= right */ size_t mid; int r; mid = (left + right) / 2; /* FIXME? avoid recomparing a common prefix */ r = strcmp(s, strings + s_table[mid]); if (r == 0) { *value = i_table[mid]; return 1; } if (r < 0) right = mid - 1; else left = mid + 1; } return 0; } inline static const char *i2s_direct__(const char *strings, const unsigned *table, int min, int max, int v) { unsigned off; if (v < min || v > max) return NULL; off = table[v - min]; if (off != -1u) return strings + off; return NULL; } inline static const char *i2s_bsearch__(const char *strings, const int *i_table, const unsigned *s_table, size_t n, int v) { ssize_t left, right; left = 0; right = n - 1; while (left <= right) { /* invariant: left <= x <= right */ size_t mid; int mid_val; mid = (left + right) / 2; mid_val = i_table[mid]; if (v == mid_val) return strings + s_table[mid]; if (v < mid_val) right = mid - 1; else left = mid + 1; } return NULL; } struct transtab { int value; unsigned offset; }; #endif audit-userspace-4.0.5/lib/gen_tables64.c000066400000000000000000000437671501761310600200260ustar00rootroot00000000000000/* gen_tables64.c -- Generator of lookup tables with 64-bit support. * Copyright 2025 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb (64-bit extensions) * Based on previous work by Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MS_DIRSYNC #include #endif #include "gen_tables64.h" #include "libaudit.h" #include "auparse-defs.h" /* This is from asm/ipc.h. Copying it for now as some platforms * * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 #define DIPC 25 /* * Defines EHWPOISON to the value found in uapi/asm-generic/errno.h, * which is correct for most (but not all architectures). */ #ifndef EHWPOISON #define EHWPOISON 133 #endif /* The ratio of table size to number of non-empty elements allowed for a "direct" s2i table; if the ratio would be bigger, bsearch tables are used instead. 2 looks like a lot at a first glance, but the bsearch tables need twice as much space per element, so with the ratio equal to 2 the direct table uses no more memory and is faster. */ #define DIRECT_THRESHOLD 2 /* Allow more than one string defined for a single integer value */ static bool allow_duplicate_ints; /* = false; */ /* Flag to indicate if we're generating 64-bit tables */ static bool use_64bit = false; struct value { int64_t val; /* Changed from int to int64_t to support 64-bit values */ const char *s; size_t s_offset; size_t orig_index; }; /* The mapping to store. */ static struct value values[] = { #define _S(VAL, S) { (VAL), (S), 0, 0 }, #include TABLE_H #undef _S }; #define NUM_VALUES (sizeof(values) / sizeof(*values)) /* Compare two "struct value" members by name. */ static int cmp_value_strings(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; return strcmp(a->s, b->s); } /* Compare two "struct value" members by value. */ static int cmp_value_vals(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->val > b->val) return 1; if (a->val < b->val) return -1; /* Preserve the original order if there is an ambiguity, to always use the first specified value. */ if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Compare two "struct value" members by orig_index. */ static int cmp_value_orig_index(const void *xa, const void *xb) { const struct value *a, *b; a = xa; b = xb; if (a->orig_index > b->orig_index) return 1; if (a->orig_index < b->orig_index) return -1; return 0; } /* Output the string table, initialize values[*]->s_offset. */ static void output_strings(const char *prefix) { size_t i, offset; offset = 0; for (i = 0; i < NUM_VALUES; i++) { values[i].s_offset = offset; offset += strlen(values[i].s) + 1; } printf("static const char %s_strings[] = \"", prefix); assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES; i++) { const char *c; if (i != 0 && i % 10 == 0) fputs("\"\n" "\t\"", stdout); for (c = values[i].s; *c != '\0'; c++) { assert(*c != '"' && *c != '\\' && isprint((unsigned char)*c)); putc(*c, stdout); } if (i != NUM_VALUES - 1) fputs("\\0", stdout); } fputs("\";\n", stdout); } /* Output the string to integer mapping code. Assume strings are all uppercase or all lowercase if specified by parameters; in that case, make the search case-insensitive. values must be sorted by strings. */ static void output_s2i(const char *prefix, bool uppercase, bool lowercase) { size_t i; for (i = 0; i < NUM_VALUES - 1; i++) { assert(strcmp(values[i].s, values[i + 1].s) <= 0); if (strcmp(values[i].s, values[i + 1].s) == 0) { fprintf(stderr, "Duplicate value `%s': %" PRId64 ", %" PRId64 "\n", values[i].s, values[i].val, values[i + 1].val); abort(); } } printf("static const unsigned %s_s2i_s[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(values[i].s_offset <= UINT_MAX); printf("%zu,", values[i].s_offset); } printf("\n" "};\n"); /* Output either int or int64_t array based on use_64bit flag */ if (use_64bit) { printf("static const int64_t %s_s2i_i[] = {", prefix); } else { printf("static const int %s_s2i_i[] = {", prefix); } for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); if (use_64bit) { printf("%" PRId64 ",", values[i].val); } else { /* For 32-bit compatibility, check if values fit in 32-bit int range */ if (values[i].val > INT_MAX || values[i].val < INT_MIN) { fprintf(stderr, "Warning: Value %" PRId64 " exceeds 32-bit int range. " "Consider using --64bit option.\n", values[i].val); } printf("%d,", (int)values[i].val); } } fputs("\n" "};\n", stdout); assert(!(uppercase && lowercase)); if (uppercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISLOWER(*c)); } } else if (lowercase) { for (i = 0; i < NUM_VALUES; i++) { const char *c; for (c = values[i].s; *c != '\0'; c++) assert(isascii((unsigned char)*c) && !GT_ISUPPER(*c)); } } /* Generate the appropriate s2i function based on 32/64-bit mode */ if (use_64bit) { if (uppercase || lowercase) { printf("static int %s_s2i(const char *s, int64_t *value) {\n" "\tsize_t len, i;\n" "\t if (s == NULL || value == NULL)\n" "\t\treturn 0;\n" "\tlen = strlen(s);\n" "\t{ char copy[len + 1];\n" "\tfor (i = 0; i < len; i++) {\n" "\t\tchar c = s[i];\n", prefix); if (uppercase) fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' " ": c;\n", stdout); else fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' " ": c;\n", stdout); printf("\t}\n" "\tcopy[i] = 0;\n" "\treturn s2i_64__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, " "copy, value);\n" "\t}\n" "}\n", prefix, prefix, prefix, NUM_VALUES); } else { printf("static int %s_s2i(const char *s, int64_t *value) {\n" "\treturn s2i_64__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, " "value);\n" "}\n", prefix, prefix, prefix, prefix, NUM_VALUES); } } else { /* Original 32-bit code */ if (uppercase || lowercase) { printf("static int %s_s2i(const char *s, int *value) {\n" "\tsize_t len, i;\n" "\t if (s == NULL || value == NULL)\n" "\t\treturn 0;\n" "\tlen = strlen(s);\n" "\t{ char copy[len + 1];\n" "\tfor (i = 0; i < len; i++) {\n" "\t\tchar c = s[i];\n", prefix); if (uppercase) fputs("\t\tcopy[i] = GT_ISLOWER(c) ? c - 'a' + 'A' " ": c;\n", stdout); else fputs("\t\tcopy[i] = GT_ISUPPER(c) ? c - 'A' + 'a' " ": c;\n", stdout); printf("\t}\n" "\tcopy[i] = 0;\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, " "copy, value);\n" "\t}\n" "}\n", prefix, prefix, prefix, NUM_VALUES); } else { printf("static int %s_s2i(const char *s, int *value) {\n" "\treturn s2i__(%s_strings, %s_s2i_s, %s_s2i_i, %zu, s, " "value);\n" "}\n", prefix, prefix, prefix, prefix, NUM_VALUES); } } } /* Output the string to integer mapping table. values must be sorted by strings. */ static void output_i2s(const char *prefix) { struct value *unique_values; int64_t min_val, max_val; size_t i, n; assert(NUM_VALUES > 0); for (i = 0; i < NUM_VALUES - 1; i++) { assert(values[i].val <= values[i + 1].val); if (!allow_duplicate_ints && values[i].val == values[i + 1].val) { fprintf(stderr, "Duplicate value %" PRId64 ": `%s', `%s'\n", values[i].val, values[i].s, values[i + 1].s); abort(); } } unique_values = malloc(NUM_VALUES * sizeof(*unique_values)); if (unique_values == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } n = 0; for (i = 0; i < NUM_VALUES; i++) { if (n == 0 || unique_values[n - 1].val != values[i].val) { unique_values[n] = values[i]; n++; } } min_val = unique_values[0].val; max_val = unique_values[n - 1].val; /* Check if the direct table approach is feasible */ /* For 64-bit values, we need to be more restrictive with direct tables * to avoid huge memory usage */ bool use_direct = false; int64_t table_size = (int64_t)max_val - (int64_t)min_val + 1; if (use_64bit) { /* For 64-bit mode: Only use direct tables if the range is manageable * (under 1024 entries) */ if (table_size > 0 && table_size < 1024 && ((double)table_size / n <= DIRECT_THRESHOLD)) { use_direct = true; } } else { /* Original 32-bit criteria */ if (((double)max_val - (double)min_val) / n <= DIRECT_THRESHOLD) { use_direct = true; } } if (use_direct) { int64_t next_index; printf("static const unsigned %s_i2s_direct[] = {", prefix); next_index = min_val; i = 0; for (;;) { if ((next_index - min_val) % 10 == 0) fputs("\n\t", stdout); while (i < n && unique_values[i].val < next_index) /* This can happen if (allow_duplicate_ints) */ i++; if (i < n && unique_values[i].val == next_index) { assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } else fputs("-1u,", stdout); if (next_index == max_val) /* Done like this to avoid integer overflow */ break; next_index++; } printf("\n" "};\n"); if (use_64bit) { printf("static const char *%s_i2s(int64_t v) {\n" "\treturn i2s_64_direct__(%s_strings, %s_i2s_direct, %" PRId64 ", " "%" PRId64 ", v);\n" "}\n", prefix, prefix, prefix, min_val, max_val); } else { printf("static const char *%s_i2s(int v) {\n" "\treturn i2s_direct__(%s_strings, %s_i2s_direct, %d, " "%d, v);\n" "}\n", prefix, prefix, prefix, (int)min_val, (int)max_val); } } else { /* Use binary search tables */ if (use_64bit) { printf("static const int64_t %s_i2s_i[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%" PRId64 ",", unique_values[i].val); } } else { printf("static const int %s_i2s_i[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("%d,", (int)unique_values[i].val); } } printf("\n" "};\n" "static const unsigned %s_i2s_s[] = {", prefix); for (i = 0; i < n; i++) { if (i % 10 == 0) fputs("\n\t", stdout); assert(unique_values[i].s_offset <= UINT_MAX); printf("%zu,", unique_values[i].s_offset); } printf("\n" "};\n"); if (use_64bit) { printf("static const char *%s_i2s(int64_t v) {\n" "\treturn i2s_64_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, " "%zu, v);\n" "}\n", prefix, prefix, prefix, prefix, n); } else { printf("static const char *%s_i2s(int v) {\n" "\treturn i2s_bsearch__(%s_strings, %s_i2s_i, %s_i2s_s, " "%zu, v);\n" "}\n", prefix, prefix, prefix, prefix, n); } } free(unique_values); } /* Output the string to integer mapping table as a transtab[]. values must be sorted in the desired order. */ static void output_i2s_transtab(const char *prefix) { size_t i; char *uc_prefix; if (use_64bit) { printf("static const struct transtab64 %s_table[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("{%" PRId64 ",%zu},", values[i].val, values[i].s_offset); } } else { printf("static const struct transtab %s_table[] = {", prefix); for (i = 0; i < NUM_VALUES; i++) { if (i % 10 == 0) fputs("\n\t", stdout); printf("{%d,%zu},", (int)values[i].val, values[i].s_offset); } } uc_prefix = strdup(prefix); if (uc_prefix == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); abort(); } for (i = 0; uc_prefix[i] != '\0'; i++) uc_prefix[i] = toupper((unsigned char)uc_prefix[i]); printf("\n" "};\n" "#define %s_NUM_ENTRIES " "(sizeof(%s_table) / sizeof(*%s_table))\n", uc_prefix, prefix, prefix); free(uc_prefix); } int main(int argc, char **argv) { bool gen_i2s, gen_i2s_transtab, gen_s2i, uppercase, lowercase; char *prefix; size_t i; /* This is required by gen_tables.h */ assert(NUM_VALUES <= (SSIZE_MAX / 2 + 1)); /* To make sure GT_ISUPPER and GT_ISLOWER work. */ assert('Z' == 'A' + 25 && 'z' == 'a' + 25); gen_i2s = false; gen_i2s_transtab = false; gen_s2i = false; uppercase = false; lowercase = false; prefix = NULL; assert (argc > 1); for (i = 1; i < (size_t)argc; i++) { if (strcmp(argv[i], "--i2s") == 0) gen_i2s = true; else if (strcmp(argv[i], "--i2s-transtab") == 0) gen_i2s_transtab = true; else if (strcmp(argv[i], "--s2i") == 0) gen_s2i = true; else if (strcmp(argv[i], "--uppercase") == 0) uppercase = true; else if (strcmp(argv[i], "--lowercase") == 0) lowercase = true; else if (strcmp(argv[i], "--duplicate-ints") == 0) allow_duplicate_ints = true; else if (strcmp(argv[i], "--64bit") == 0) use_64bit = true; else { assert(*argv[i] != '-'); assert(prefix == NULL); prefix = argv[i]; } } assert(prefix != NULL); assert(!(uppercase && lowercase)); printf("/* This is a generated file, see Makefile.am for its " "inputs. */\n"); /* Add include for inttypes.h if using 64-bit mode */ if (use_64bit) { printf("#include \n"); } for (i = 0; i < NUM_VALUES; i++) values[i].orig_index = i; qsort(values, NUM_VALUES, sizeof(*values), cmp_value_strings); /* FIXME? if (gen_s2i), sort the strings in some other order (e.g. "first 4 nodes in BFS of the bsearch tree first") to use the cache better. */ /* FIXME? If the only thing generated is a transtab, keep the strings in the original order to use the cache better. */ output_strings(prefix); if (gen_s2i) output_s2i(prefix, uppercase, lowercase); if (gen_i2s) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_vals); output_i2s(prefix); } if (gen_i2s_transtab) { qsort(values, NUM_VALUES, sizeof(*values), cmp_value_orig_index); output_i2s_transtab(prefix); } return EXIT_SUCCESS; } audit-userspace-4.0.5/lib/gen_tables64.h000066400000000000000000000074111501761310600200150ustar00rootroot00000000000000/* gen_tables64.h -- Declarations used for 64-bit lookup tables. * Copyright 2025 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Base on previous work by Miloslav Trmač */ #ifndef GEN_TABLES64_H__ #define GEN_TABLES64_H__ #include #include /* Assumes ASCII; verified in gen_tables.c. */ #define GT_ISUPPER(X) ((X) >= 'A' && (X) <= 'Z') #define GT_ISLOWER(X) ((X) >= 'a' && (X) <= 'z') /* 32-bit versions (original) */ inline static int s2i__(const char *strings, const unsigned *s_table, const int *i_table, size_t n, const char *s, int *value); inline static const char *i2s_direct__(const char *strings, const unsigned *table, int min, int max, int v); inline static const char *i2s_bsearch__(const char *strings, const int *i_table, const unsigned *s_table, size_t n, int v); /* 64-bit versions */ inline static int s2i_64__(const char *strings, const unsigned *s_table, const int64_t *i_table, size_t n, const char *s, int64_t *value) { ssize_t left, right; left = 0; right = n - 1; while (left <= right) { /* invariant: left <= x <= right */ size_t mid; int r; mid = (left + right) / 2; /* FIXME? avoid recomparing a common prefix */ r = strcmp(s, strings + s_table[mid]); if (r == 0) { *value = i_table[mid]; return 1; } if (r < 0) right = mid - 1; else left = mid + 1; } return 0; } inline static const char *i2s_64_direct__(const char *strings, const unsigned *table, int64_t min, int64_t max, int64_t v) { unsigned off; if (v < min || v > max) return NULL; // Cast to uint64_t to avoid potential overflow in 32-bit index calculation uint64_t index = (uint64_t)(v - min); if (index > SIZE_MAX) /* Check if the index would overflow size_t */ return NULL; off = table[(size_t)index]; if (off != -1u) return strings + off; return NULL; } inline static const char *i2s_64_bsearch__(const char *strings, const int64_t *i_table, const unsigned *s_table, size_t n, int64_t v) { ssize_t left, right; left = 0; right = n - 1; while (left <= right) { /* invariant: left <= x <= right */ size_t mid; int64_t mid_val; mid = (left + right) / 2; mid_val = i_table[mid]; if (v == mid_val) return strings + s_table[mid]; if (v < mid_val) right = mid - 1; else left = mid + 1; } return NULL; } struct transtab64 { int64_t value; unsigned offset; }; /* Include original 32-bit function implementations */ #include "gen_tables.h" #endif /* GEN_TABLES64_H__ */ audit-userspace-4.0.5/lib/i386_table.h000066400000000000000000000245121501761310600174010ustar00rootroot00000000000000/* i386_table.h -- * Copyright 2005-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(0, "restart_syscall") _S(1, "exit") _S(2, "fork") _S(3, "read") _S(4, "write") _S(5, "open") _S(6, "close") _S(7, "waitpid") _S(8, "creat") _S(9, "link") _S(10, "unlink") _S(11, "execve") _S(12, "chdir") _S(13, "time") _S(14, "mknod") _S(15, "chmod") _S(16, "lchown") _S(17, "break") _S(18, "oldstat") _S(19, "lseek") _S(20, "getpid") _S(21, "mount") _S(22, "umount") _S(23, "setuid") _S(24, "getuid") _S(25, "stime") _S(26, "ptrace") _S(27, "alarm") _S(28, "oldfstat") _S(29, "pause") _S(30, "utime") _S(31, "stty") _S(32, "gtty") _S(33, "access") _S(34, "nice") _S(35, "ftime") _S(36, "sync") _S(37, "kill") _S(38, "rename") _S(39, "mkdir") _S(40, "rmdir") _S(41, "dup") _S(42, "pipe") _S(43, "times") _S(44, "prof") _S(45, "brk") _S(46, "setgid") _S(47, "getgid") _S(48, "signal") _S(49, "geteuid") _S(50, "getegid") _S(51, "acct") _S(52, "umount2") _S(53, "lock") _S(54, "ioctl") _S(55, "fcntl") _S(56, "mpx") _S(57, "setpgid") _S(58, "ulimit") _S(59, "oldolduname") _S(60, "umask") _S(61, "chroot") _S(62, "ustat") _S(63, "dup2") _S(64, "getppid") _S(65, "getpgrp") _S(66, "setsid") _S(67, "sigaction") _S(68, "sgetmask") _S(69, "ssetmask") _S(70, "setreuid") _S(71, "setregid") _S(72, "sigsuspend") _S(73, "sigpending") _S(74, "sethostname") _S(75, "setrlimit") _S(76, "getrlimit") _S(77, "getrusage") _S(78, "gettimeofday") _S(79, "settimeofday") _S(80, "getgroups") _S(81, "setgroups") _S(82, "select") _S(83, "symlink") _S(84, "oldlstat") _S(85, "readlink") _S(86, "uselib") _S(87, "swapon") _S(88, "reboot") _S(89, "readdir") _S(90, "mmap") _S(91, "munmap") _S(92, "truncate") _S(93, "ftruncate") _S(94, "fchmod") _S(95, "fchown") _S(96, "getpriority") _S(97, "setpriority") _S(98, "profil") _S(99, "statfs") _S(100, "fstatfs") _S(101, "ioperm") _S(102, "socketcall") _S(103, "syslog") _S(104, "setitimer") _S(105, "getitimer") _S(106, "stat") _S(107, "lstat") _S(108, "fstat") _S(109, "olduname") _S(110, "iopl") _S(111, "vhangup") _S(112, "idle") _S(113, "vm86old") _S(114, "wait4") _S(115, "swapoff") _S(116, "sysinfo") _S(117, "ipc") _S(118, "fsync") _S(119, "sigreturn") _S(120, "clone") _S(121, "setdomainname") _S(122, "uname") _S(123, "modify_ldt") _S(124, "adjtimex") _S(125, "mprotect") _S(126, "sigprocmask") _S(127, "create_module") _S(128, "init_module") _S(129, "delete_module") _S(130, "get_kernel_syms") _S(131, "quotactl") _S(132, "getpgid") _S(133, "fchdir") _S(134, "bdflush") _S(135, "sysfs") _S(136, "personality") _S(137, "afs_syscall") _S(138, "setfsuid") _S(139, "setfsgid") _S(140, "_llseek") _S(141, "getdents") _S(142, "_newselect") _S(143, "flock") _S(144, "msync") _S(145, "readv") _S(146, "writev") _S(147, "getsid") _S(148, "fdatasync") _S(149, "_sysctl") _S(150, "mlock") _S(151, "munlock") _S(152, "mlockall") _S(153, "munlockall") _S(154, "sched_setparam") _S(155, "sched_getparam") _S(156, "sched_setscheduler") _S(157, "sched_getscheduler") _S(158, "sched_yield") _S(159, "sched_get_priority_max") _S(160, "sched_get_priority_min") _S(161, "sched_rr_get_interval") _S(162, "nanosleep") _S(163, "mremap") _S(164, "setresuid") _S(165, "getresuid") _S(166, "vm86") _S(167, "query_module") _S(168, "poll") _S(169, "nfsservctl") _S(170, "setresgid") _S(171, "getresgid") _S(172, "prctl") _S(173, "rt_sigreturn") _S(174, "rt_sigaction") _S(175, "rt_sigprocmask") _S(176, "rt_sigpending") _S(177, "rt_sigtimedwait") _S(178, "rt_sigqueueinfo") _S(179, "rt_sigsuspend") _S(180, "pread64") _S(181, "pwrite64") _S(182, "chown") _S(183, "getcwd") _S(184, "capget") _S(185, "capset") _S(186, "sigaltstack") _S(187, "sendfile") _S(188, "getpmsg") _S(189, "putpmsg") _S(190, "vfork") _S(191, "ugetrlimit") _S(192, "mmap2") _S(193, "truncate64") _S(194, "ftruncate64") _S(195, "stat64") _S(196, "lstat64") _S(197, "fstat64") _S(198, "lchown32") _S(199, "getuid32") _S(200, "getgid32") _S(201, "geteuid32") _S(202, "getegid32") _S(203, "setreuid32") _S(204, "setregid32") _S(205, "getgroups32") _S(206, "setgroups32") _S(207, "fchown32") _S(208, "setresuid32") _S(209, "getresuid32") _S(210, "setresgid32") _S(211, "getresgid32") _S(212, "chown32") _S(213, "setuid32") _S(214, "setgid32") _S(215, "setfsuid32") _S(216, "setfsgid32") _S(217, "pivot_root") _S(218, "mincore") _S(219, "madvise") _S(219, "madvise1") _S(220, "getdents64") _S(221, "fcntl64") _S(224, "gettid") _S(225, "readahead") _S(226, "setxattr") _S(227, "lsetxattr") _S(228, "fsetxattr") _S(229, "getxattr") _S(230, "lgetxattr") _S(231, "fgetxattr") _S(232, "listxattr") _S(233, "llistxattr") _S(234, "flistxattr") _S(235, "removexattr") _S(236, "lremovexattr") _S(237, "fremovexattr") _S(238, "tkill") _S(239, "sendfile64") _S(240, "futex") _S(241, "sched_setaffinity") _S(242, "sched_getaffinity") _S(243, "set_thread_area") _S(244, "get_thread_area") _S(245, "io_setup") _S(246, "io_destroy") _S(247, "io_getevents") _S(248, "io_submit") _S(249, "io_cancel") _S(250, "fadvise64") _S(252, "exit_group") _S(253, "lookup_dcookie") _S(254, "epoll_create") _S(255, "epoll_ctl") _S(256, "epoll_wait") _S(257, "remap_file_pages") _S(258, "set_tid_address") _S(259, "timer_create") _S(260, "timer_settime") _S(261, "timer_gettime") _S(262, "timer_getoverrun") _S(263, "timer_delete") _S(264, "clock_settime") _S(265, "clock_gettime") _S(266, "clock_getres") _S(267, "clock_nanosleep") _S(268, "statfs64") _S(269, "fstatfs64") _S(270, "tgkill") _S(271, "utimes") _S(272, "fadvise64_64") _S(273, "vserver") _S(274, "mbind") _S(275, "get_mempolicy") _S(276, "set_mempolicy") _S(277, "mq_open") _S(278, "mq_unlink") _S(279, "mq_timedsend") _S(280, "mq_timedreceive") _S(281, "mq_notify") _S(282, "mq_getsetattr") _S(283, "sys_kexec_load") _S(284, "waitid") // 285 is setaltroot but it is not defined (yet) _S(286, "add_key") _S(287, "request_key") _S(288, "keyctl") _S(289, "ioprio_set") _S(290, "ioprio_get") _S(291, "inotify_init") _S(292, "inotify_add_watch") _S(293, "inotify_rm_watch") _S(294, "migrate_pages") _S(295, "openat") _S(296, "mkdirat") _S(297, "mknodat") _S(298, "fchownat") _S(299, "futimesat") _S(300, "fstatat64") _S(301, "unlinkat") _S(302, "renameat") _S(303, "linkat") _S(304, "symlinkat") _S(305, "readlinkat") _S(306, "fchmodat") _S(307, "faccessat") _S(308, "pselect6") _S(309, "ppoll") _S(310, "unshare") _S(311, "set_robust_list") _S(312, "get_robust_list") _S(313, "splice") _S(314, "sync_file_range") _S(315, "tee") _S(316, "vmsplice") _S(317, "move_pages") _S(318, "getcpu") _S(319, "epoll_pwait") _S(320, "utimensat") _S(321, "signalfd") _S(322, "timerfd_create") _S(323, "eventfd") _S(324, "fallocate") _S(325, "timerfd_settime") _S(326, "timerfd_gettime") _S(327, "signalfd4") _S(328, "eventfd2") _S(329, "epoll_create1") _S(330, "dup3") _S(331, "pipe2") _S(332, "inotify_init1") _S(333, "preadv") _S(334, "pwritev") _S(335, "rt_tgsigqueueinfo") _S(336, "perf_event_open") _S(337, "recvmmsg") _S(338, "fanotify_init") _S(339, "fanotify_mark") _S(340, "prlimit64") _S(341, "name_to_handle_at") _S(342, "open_by_handle_at") _S(343, "clock_adjtime") _S(344, "syncfs") _S(345, "sendmmsg") _S(346, "setns") _S(347, "process_vm_readv") _S(348, "process_vm_writev") _S(349, "kcmp") _S(350, "finit_module") _S(351, "sched_setattr") _S(352, "sched_getattr") _S(353, "renameat2") _S(354, "seccomp") _S(355, "getrandom") _S(356, "memfd_create") _S(357, "bpf") _S(358, "execveat") _S(359, "socket") _S(360, "socketpair") _S(361, "bind") _S(362, "connect") _S(363, "listen") _S(364, "accept4") _S(365, "getsockopt") _S(366, "setsockopt") _S(367, "getsockname") _S(368, "getpeername") _S(369, "sendto") _S(370, "sendmsg") _S(371, "recvfrom") _S(372, "recvmsg") _S(373, "shutdown") _S(374, "userfaultfd") _S(375, "membarrier") _S(376, "mlock2") _S(377, "copy_file_range") _S(378, "preadv2") _S(379, "pwritev2") _S(380, "pkey_mprotect") _S(381, "pkey_alloc") _S(382, "pkey_free") _S(383, "statx") _S(384, "arch_prctl") _S(385, "io_pgetevents") _S(386, "rseq") _S(393, "semget") _S(394, "semctl") _S(395, "shmget") _S(396, "shmctl") _S(397, "shmat") _S(398, "shmdt") _S(399, "msgget") _S(400, "msgsnd") _S(401, "msgrcv") _S(402, "msgctl") _S(403, "clock_gettime64") _S(404, "clock_settime64") _S(405, "clock_adjtime64") _S(406, "clock_getres_time64") _S(407, "clock_nanosleep_time64") _S(408, "timer_gettime64") _S(409, "timer_settime64") _S(410, "timerfd_gettime64") _S(411, "timerfd_settime64") _S(412, "utimensat_time64") _S(413, "pselect6_time64") _S(414, "ppoll_time64") _S(416, "io_pgetevents_time64") _S(417, "recvmmsg_time64") _S(418, "mq_timedsend_time64") _S(419, "mq_timedreceive_time64") _S(420, "semtimedop_time64") _S(421, "rt_sigtimedwait_time64") _S(422, "futex_time64") _S(423, "sched_rr_get_interval64") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/libaudit.c000066400000000000000000001454501501761310600173360ustar00rootroot00000000000000/* libaudit.c -- * Copyright 2004-2009,2012,2014,2016-17,2020 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith * Richard Guy Briggs */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* O_NOFOLLOW needs gnu defined */ #include /* for PATH_MAX */ #include #include /* AF_MAX */ #ifdef HAVE_LIBCAP_NG #include #endif #ifdef WITH_IO_URING #include #endif #include "libaudit.h" #include "private.h" #include "errormsg.h" #include "common.h" /* #defines for the audit failure query */ #define CONFIG_FILE "/etc/libaudit.conf" #ifndef IORING_OP_LAST #define IORING_OP_LAST 37 #endif /* Local prototypes */ struct nv_pair { const char *name; const char *value; }; struct kw_pair { const char *name; int (*parser)(const char *, int); }; struct nv_list { const char *name; int option; }; struct libaudit_conf { auditfail_t failure_action; }; static const struct nv_list failure_actions[] = { {"ignore", FAIL_IGNORE }, {"log", FAIL_LOG }, {"terminate", FAIL_TERMINATE }, { NULL, 0 } }; int _audit_permadded = 0; int _audit_archadded = 0; int _audit_syscalladded = 0; int _audit_exeadded = 0; int _audit_filterfsadded = 0; unsigned int _audit_elf = 0U; static struct libaudit_conf config; static int audit_failure_parser(const char *val, int line); static int audit_name_to_uid(const char *name, uid_t *auid); static int audit_name_to_gid(const char *name, gid_t *gid); static char* filter_supported_syscalls(const char* syscalls, int machine) __attr_dealloc_free; static const struct kw_pair keywords[] = { {"failure_action", audit_failure_parser }, { NULL, NULL } }; static int audit_priority(int xerrno) { /* If they've compiled their own kernel and did not include * the audit subsystem, they will get ECONNREFUSED. We'll * demote the message to debug so its not lost entirely. */ if (xerrno == ECONNREFUSED) return LOG_DEBUG; else return LOG_WARNING; } int audit_request_status(int fd) { int rc = audit_send(fd, AUDIT_GET, NULL, 0); if (rc < 0) audit_msg(audit_priority(errno), "Error sending status request (%s)", strerror(-rc)); return rc; } /* * Set everything to its default value */ static void clear_config(void) { config.failure_action = FAIL_IGNORE; } /* Get 1 line from file */ static char *get_line(FILE *f, char *buf, size_t len) { if (fgets(buf, len, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) *ptr = 0; return buf; } return NULL; } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr, *saved=NULL; nv->name = NULL; nv->value = NULL; ptr = audit_strsplit_r(buf, &saved); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = audit_strsplit_r(NULL, &saved); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = audit_strsplit_r(NULL, &saved); if (ptr == NULL) return 1; nv->value = ptr; /* Make sure there's nothing else */ ptr = audit_strsplit_r(NULL, &saved); if (ptr) return 1; /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int audit_failure_parser(const char *val, int line) { int i; audit_msg(LOG_DEBUG, "audit_failure_parser called with: %s", val); for (i=0; failure_actions[i].name != NULL; i++) { if (strcasecmp(val, failure_actions[i].name) == 0) { config.failure_action = failure_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", val, line); return 1; } /* * Read the /etc/libaudit.conf file and all tunables. */ static int load_libaudit_config(const char *path) { int fd, rc, lineno = 1; struct stat st; FILE *f; char buf[128]; /* open the file */ rc = open(path, O_NOFOLLOW|O_RDONLY|O_CLOEXEC); if (rc < 0) { if (errno != ENOENT) { audit_msg(LOG_ERR, "Error opening %s (%s)", path, strerror(errno)); return 1; } audit_msg(LOG_WARNING, "Config file %s doesn't exist, skipping", path); return 0; } fd = rc; /* check the file's permissions: owned by root, not world writable, * not symlink. */ audit_msg(LOG_DEBUG, "Config file %s opened for parsing", path); if (fstat(fd, &st) < 0) { audit_msg(LOG_ERR, "Error fstat'ing %s (%s)", path, strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { audit_msg(LOG_ERR, "Error - %s isn't owned by root", path); close(fd); return 1; } if (st.st_gid != 0 && (st.st_mode & S_IWGRP) == S_IWGRP) { audit_msg(LOG_ERR, "Error - %s is group writable", path); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { audit_msg(LOG_ERR, "Error - %s is world writable", path); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { audit_msg(LOG_ERR, "Error - %s is not a regular file", path); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rme"); if (f == NULL) { audit_msg(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf, sizeof(buf))) { // convert line into name-value pair const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. audit_msg(LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, path); break; case 2: // no '=' sign audit_msg(LOG_ERR, "Missing equal sign for line %d in %s", lineno, path); break; default: // something else went wrong... audit_msg(LOG_ERR, "Unknown error for line %d in %s", lineno, path); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { audit_msg(LOG_ERR, "Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, path); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(nv.value, lineno); if (rc != 0) { fclose(f); return 1; // local parser puts message out } lineno++; } fclose(f); return 0; } /* * This function is called to get the value of the failure_action * tunable stored in /etc/libaudit.conf. The function returns 1 if * the tunable is not found or there is an error. If the tunable is found, * 0 is returned the the tunable value is saved in the failmode parameter. */ int get_auditfail_action(auditfail_t *failmode) { clear_config(); if (load_libaudit_config(CONFIG_FILE)) { *failmode = config.failure_action; return 1; } *failmode = config.failure_action; return 0; } int audit_set_enabled(int fd, uint32_t enabled) { int rc; struct audit_status s; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_ENABLED; s.enabled = enabled; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending enable request (%s)", strerror(-rc)); return rc; } /* * This function will return 0 if auditing is NOT enabled and * 1 if enabled, and -1 on error. */ int audit_is_enabled(int fd) { int rc; if (fd < 0) return 0; if ((rc = audit_request_status(fd)) > 0) { struct audit_reply rep; int i; int timeout = 40; /* tenths of seconds */ struct pollfd pfd[1]; pfd[0].fd = fd; pfd[0].events = POLLIN; for (i = 0; i < timeout; i++) { do { rc = poll(pfd, 1, 100); } while (rc < 0 && errno == EINTR); rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING,0); if (rc > 0) { /* If we get done or error, break out */ if (rep.type == NLMSG_DONE || rep.type == NLMSG_ERROR) break; /* If its not status, keep looping */ if (rep.type != AUDIT_GET) continue; /* Found it... */ return rep.status->enabled; } } } if (rc == -ECONNREFUSED) { /* This is here to let people that build their own kernel and disable the audit system get in. ECONNREFUSED is issued by the kernel when there is "no on listening". */ return 0; } else if (rc == -EPERM && !audit_can_control()) { /* If we get this, then the kernel supports auditing * but we don't have enough privilege to write to the * socket. Therefore, we have already been authenticated * and we are a common user. Just act as though auditing * is not enabled. Any other error we take seriously. * This is here basically to satisfy Xscreensaver. */ return 0; } return -1; } int audit_set_failure(int fd, uint32_t failure) { int rc; struct audit_status s; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_FAILURE; s.failure = failure; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending failure mode request (%s)", strerror(-rc)); return rc; } /* * This function returns -1 on error and 1 on success. */ int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) { struct audit_status s; struct audit_reply rep; struct pollfd pfd[1]; int rc; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_PID; s.pid = pid; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) { audit_msg(audit_priority(errno), "Error setting audit daemon pid (%s)", strerror(-rc)); return rc; } if (wmode == WAIT_NO) return 1; /* Now we'll see if there's any reply message. This only happens on error. It is not fatal if there is no message. As a matter of fact, we don't do anything with the message besides gobble it. */ pfd[0].fd = fd; pfd[0].events = POLLIN; do { rc = poll(pfd, 1, 100); /* .1 second */ } while (rc < 0 && errno == EINTR); if (audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0)) ; // intentionally empty return 1; } int audit_set_rate_limit(int fd, uint32_t limit) { int rc; struct audit_status s; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_RATE_LIMIT; s.rate_limit = limit; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending rate limit request (%s)", strerror(-rc)); return rc; } int audit_set_backlog_limit(int fd, uint32_t limit) { int rc; struct audit_status s; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_BACKLOG_LIMIT; s.backlog_limit = limit; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending backlog limit request (%s)", strerror(-rc)); return rc; } int audit_set_backlog_wait_time(int fd, uint32_t bwt) { int rc = -1; #if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME == 1 || \ HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME == 1 struct audit_status s; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_BACKLOG_WAIT_TIME; s.backlog_wait_time = bwt; rc = audit_send(fd, AUDIT_SET, &s, sizeof(s)); if (rc < 0) audit_msg(audit_priority(errno), "Error sending backlog limit request (%s)", strerror(-rc)); #endif return rc; } int audit_reset_lost(int fd) { int rc; int seq; struct audit_status s; if ((audit_get_features() & AUDIT_FEATURE_BITMAP_LOST_RESET) == 0) return -EAU_FIELDNOSUPPORT; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_LOST; s.lost = 0; rc = __audit_send(fd, AUDIT_SET, &s, sizeof(s), &seq); if (rc < 0) audit_msg(audit_priority(errno), "Error sending lost reset request (%s)", strerror(-rc)); return rc; } int audit_reset_backlog_wait_time_actual(int fd) { int rc = -1; #if HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL == 1 struct audit_status s; int seq; memset(&s, 0, sizeof(s)); s.mask = AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL; s.backlog_wait_time_actual = 0; rc = __audit_send(fd, AUDIT_SET, &s, sizeof(s), &seq); if (rc < 0) audit_msg(audit_priority(errno), "Error sending backlog wait time actual reset request (%s)", strerror(-rc)); #endif return rc; } int audit_set_feature(int fd, unsigned feature, unsigned value, unsigned lock) { #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 int rc; struct audit_features f; memset(&f, 0, sizeof(f)); f.mask = AUDIT_FEATURE_TO_MASK(feature); if (value) f.features = AUDIT_FEATURE_TO_MASK(feature); if (lock) f.lock = AUDIT_FEATURE_TO_MASK(feature); rc = audit_send(fd, AUDIT_SET_FEATURE, &f, sizeof(f)); if (rc < 0) audit_msg(audit_priority(errno), "Error setting feature (%s)", strerror(-rc)); return rc; #else errno = EINVAL; return -1; #endif } int audit_request_features(int fd) { #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 int rc; struct audit_features f; memset(&f, 0, sizeof(f)); rc = audit_send(fd, AUDIT_GET_FEATURE, &f, sizeof(f)); if (rc < 0) audit_msg(audit_priority(errno), "Error getting feature (%s)", strerror(-rc)); return rc; #else errno = EINVAL; return -1; #endif } extern int audit_set_loginuid_immutable(int fd) { #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 return audit_set_feature(fd, AUDIT_FEATURE_LOGINUID_IMMUTABLE, 1, 1); #else errno = EINVAL; return -1; #endif } #define AUDIT_FEATURES_UNSET 0xFFFFFFFF #define AUDIT_FEATURES_UNSUPPORTED 0xEFFFFFFF static uint32_t features_bitmap = AUDIT_FEATURES_UNSET; static void load_feature_bitmap(void) { int rc, fd; fd = audit_open(); if (fd < 0) { features_bitmap = AUDIT_FEATURES_UNSUPPORTED; return; } #if defined(HAVE_STRUCT_AUDIT_STATUS_FEATURE_BITMAP) if (audit_request_status(fd) > 0) { struct audit_reply rep; int i; int timeout = 40; /* tenths of seconds */ struct pollfd pfd[1]; pfd[0].fd = fd; pfd[0].events = POLLIN; for (i = 0; i < timeout; i++) { do { rc = poll(pfd, 1, 100); } while (rc < 0 && errno == EINTR); rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING,0); if (rc > 0) { /* If we get done or error, break out */ if (rep.type == NLMSG_DONE || rep.type == NLMSG_ERROR) break; /* If its not status, keep looping */ if (rep.type != AUDIT_GET) continue; /* Found it... */ features_bitmap = rep.status->feature_bitmap; audit_close(fd); return; } } } #endif features_bitmap = AUDIT_FEATURES_UNSUPPORTED; audit_close(fd); } uint32_t audit_get_features(void) { if (features_bitmap == AUDIT_FEATURES_UNSET) load_feature_bitmap(); if (features_bitmap == AUDIT_FEATURES_UNSUPPORTED) return 0; return features_bitmap; } int audit_request_rules_list_data(int fd) { int rc = audit_send(fd, AUDIT_LIST_RULES, NULL, 0); if (rc < 0 && rc != -EINVAL) audit_msg(audit_priority(errno), "Error sending rule list data request (%s)", strerror(-rc)); return rc; } int audit_request_signal_info(int fd) { int rc = audit_send(fd, AUDIT_SIGNAL_INFO, NULL, 0); if (rc < 0) audit_msg(LOG_WARNING, "Error sending signal_info request (%s)", strerror(-rc)); return rc; } char *audit_format_signal_info(char *buf, int len, const char *op, const struct audit_reply *rep, const char *res) { struct stat sb; char path[32], ses[16]; ssize_t rlen; snprintf(path, sizeof(path), "/proc/%u", rep->signal_info->pid); int fd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC); if (fd >= 0) { if (fstat(fd, &sb) < 0) sb.st_uid = -1; close(fd); } else sb.st_uid = -1; snprintf(path, sizeof(path), "/proc/%u/sessionid", rep->signal_info->pid); fd = open(path, O_RDONLY|O_CLOEXEC, rep->signal_info->pid); if (fd < 0) strcpy(ses, "4294967295"); else { do { rlen = read(fd, ses, sizeof(ses)); } while (rlen < 0 && errno == EINTR); close(fd); if (rlen < 0 || (size_t)rlen >= sizeof(ses)) strcpy(ses, "4294967295"); else ses[rlen] = 0; } if (rep->len == 24) snprintf(buf, len, "op=%s auid=%u uid=%u ses=%s pid=%d res=%s", op, rep->signal_info->uid, sb.st_uid, ses, rep->signal_info->pid, res); else snprintf(buf, len, "op=%s auid=%u uid=%u ses=%s pid=%d subj=%s res=%s", op,rep->signal_info->uid, sb.st_uid, ses, rep->signal_info->pid, rep->signal_info->ctx, res); return buf; } int audit_update_watch_perms(struct audit_rule_data *rule, int perms) { unsigned int i, done=0; if (rule->field_count < 1) { audit_msg(LOG_ERR, "Permissions should be preceded by other fields"); return -1; } // First see if we have an entry we are updating for (i=0; i< rule->field_count; i++) { if (rule->fields[i] == AUDIT_PERM) { rule->values[i] = perms; done = 1; } } if (!done) { // If not check to see if we have room to add a field if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) { audit_msg(LOG_ERR, "Too many fields when adding permissions"); return -2; } // Add the perm rule->fields[rule->field_count] = AUDIT_PERM; rule->fieldflags[rule->field_count] = AUDIT_EQUAL; rule->values[rule->field_count] = perms; rule->field_count++; } return 0; } int audit_add_watch(struct audit_rule_data **rulep, const char *path) { return audit_add_watch_dir(AUDIT_WATCH, rulep, path); } int audit_add_watch_dir(int type, struct audit_rule_data **rulep, const char *path) { size_t len = strlen(path); struct audit_rule_data *rule = *rulep, *tmp; if (rule && rule->field_count) { audit_msg(LOG_ERR, "Rule is not empty"); return -1; } if (type != AUDIT_WATCH && type != AUDIT_DIR) { audit_msg(LOG_ERR, "Invalid type used"); return -1; } // Use a temporary pointer to prevent memory leaks tmp = realloc(rule, len + sizeof(*rule)); if (tmp == NULL) { free(rule); *rulep = NULL; audit_msg(LOG_ERR, "Cannot realloc memory!"); return -1; } *rulep = tmp; rule = *rulep; memset(rule, 0, len + sizeof(*rule)); rule->flags = AUDIT_FILTER_EXIT; rule->action = AUDIT_ALWAYS; audit_rule_syscallbyname_data(rule, "all"); rule->field_count = 2; rule->fields[0] = type; rule->values[0] = len; rule->fieldflags[0] = AUDIT_EQUAL; rule->buflen = len; memcpy(&rule->buf[0], path, len); // Default to all permissions rule->fields[1] = AUDIT_PERM; rule->fieldflags[1] = AUDIT_EQUAL; rule->values[1] = AUDIT_PERM_READ | AUDIT_PERM_WRITE | AUDIT_PERM_EXEC | AUDIT_PERM_ATTR; _audit_permadded = 1; return 0; } int audit_add_rule_data(int fd, struct audit_rule_data *rule, int flags, int action) { int rc; rule->flags = flags; rule->action = action; rc = audit_send(fd, AUDIT_ADD_RULE, rule, sizeof(struct audit_rule_data) + rule->buflen); if (rc < 0) audit_msg(audit_priority(errno), "Error sending add rule data request (%s)", errno == EEXIST ? "Rule exists" : strerror(-rc)); return rc; } int audit_delete_rule_data(int fd, struct audit_rule_data *rule, int flags, int action) { int rc; rule->flags = flags; rule->action = action; rc = audit_send(fd, AUDIT_DEL_RULE, rule, sizeof(struct audit_rule_data) + rule->buflen); if (rc < 0) { if (rc == -ENOENT) audit_msg(LOG_WARNING, "Error sending delete rule request (No rule matches)"); else audit_msg(audit_priority(errno), "Error sending delete rule data request (%s)", strerror(-rc)); } return rc; } /* * This function is part of the directory auditing code */ int audit_trim_subtrees(int fd) { int rc = audit_send(fd, AUDIT_TRIM, NULL, 0); if (rc < 0) audit_msg(audit_priority(errno), "Error sending trim subtrees command (%s)", strerror(-rc)); return rc; } /* * This function is part of the directory auditing code */ int audit_make_equivalent(int fd, const char *mount_point, const char *subtree) { int rc; size_t len1 = strlen(mount_point); size_t len2 = strlen(subtree); struct { uint32_t sizes[2]; unsigned char buf[]; } *cmd = calloc(1, sizeof(*cmd) + len1 + len2); if (!cmd) { audit_msg(LOG_ERR, "Cannot allocate memory!"); return -ENOMEM; } cmd->sizes[0] = len1; cmd->sizes[1] = len2; memcpy(&cmd->buf[0], mount_point, len1); memcpy(&cmd->buf[len1], subtree, len2); rc = audit_send(fd, AUDIT_MAKE_EQUIV, cmd, sizeof(*cmd) + len1 + len2); if (rc < 0) audit_msg(audit_priority(errno), "Error sending make_equivalent command (%s)", strerror(-rc)); free(cmd); return rc; } /* * This function will retrieve the loginuid or -1 if there * is an error. */ uid_t audit_getloginuid(void) { uid_t uid; int in; ssize_t len; char buf[16]; errno = 0; in = open("/proc/self/loginuid", O_NOFOLLOW|O_RDONLY|O_CLOEXEC); if (in < 0) return -1; do { len = read(in, buf, sizeof(buf)); } while (len < 0 && errno == EINTR); close(in); if (len < 0 || (size_t)len >= sizeof(buf)) return -1; buf[len] = 0; errno = 0; uid = strtol(buf, 0, 10); if (errno) return -1; else return uid; } /* * This function returns 0 on success and 1 on failure */ int audit_setloginuid(uid_t uid) { char loginuid[16]; int o, count, rc = 0; errno = 0; count = snprintf(loginuid, sizeof(loginuid), "%u", uid); o = open("/proc/self/loginuid", O_NOFOLLOW|O_WRONLY|O_TRUNC|O_CLOEXEC); if (o >= 0) { int block, offset = 0; while (count > 0) { block = write(o, &loginuid[offset], (unsigned)count); if (block < 0) { if (errno == EINTR) continue; audit_msg(LOG_ERR, "Error writing loginuid"); close(o); return 1; } offset += block; count -= block; } close(o); } else { audit_msg(LOG_ERR, "Error opening /proc/self/loginuid"); rc = 1; } return rc; } /* * This function will retrieve the login session or -2 if there * is an error. */ uint32_t audit_get_session(void) { uint32_t ses; int in; ssize_t len; char buf[16]; errno = 0; in = open("/proc/self/sessionid", O_NOFOLLOW|O_RDONLY|O_CLOEXEC); if (in < 0) return -2; do { len = read(in, buf, sizeof(buf)); } while (len < 0 && errno == EINTR); close(in); if (len < 0 || (size_t)len >= sizeof(buf)) return -2; buf[len] = 0; errno = 0; ses = strtoul(buf, 0, 10); if (errno) return -2; else return ses; } static int audit_rule_syscall_data(struct audit_rule_data *rule, int scall) { int word = AUDIT_WORD(scall); int bit = AUDIT_BIT(scall); if (word > (AUDIT_BITMASK_SIZE-1)) return -1; rule->mask[word] |= bit; _audit_syscalladded = 1; return 0; } int audit_rule_syscallbyname_data(struct audit_rule_data *rule, const char *scall) { int nr, i; int machine; if (!strcmp(scall, "all")) { for (i = 0; i < AUDIT_BITMASK_SIZE; i++) rule->mask[i] = ~0; return 0; } if (!_audit_elf) machine = audit_detect_machine(); else machine = audit_elf_to_machine(_audit_elf); if (machine < 0) return -2; nr = audit_name_to_syscall(scall, machine); if (nr < 0) { if (isdigit((unsigned char)scall[0])) nr = strtol(scall, NULL, 0); } if (nr >= 0) return audit_rule_syscall_data(rule, nr); return -1; } int audit_rule_io_uringbyname_data(struct audit_rule_data *rule, const char *scall) { #ifdef WITH_IO_URING int nr; if (!strcmp(scall, "all")) { int i, rc = 0; for (i = 0; i < IORING_OP_LAST && !rc; i++) { // while names resolve if (audit_uringop_to_name(i)) rc = audit_rule_syscall_data(rule, i); } return rc; } nr = audit_name_to_uringop(scall); if (nr < 0) { if (isdigit((unsigned char)scall[0])) nr = strtol(scall, NULL, 0); } if (nr >= 0) return audit_rule_syscall_data(rule, nr); #endif return -1; } int audit_rule_interfield_comp_data(struct audit_rule_data **rulep, char *pair, int flags) { char *f = pair; char *v; int op; int field1, field2; struct audit_rule_data *rule = *rulep; if (f == NULL) return -EAU_FILTERMISSING; if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) return -EAU_FIELDTOOMANY; /* look for 2-char operators first then look for 1-char operators afterwards when found, null out the bytes under the operators to split and set value pointer just past operator bytes */ if ( (v = strstr(pair, "!=")) ) { *v++ = '\0'; *v++ = '\0'; op = AUDIT_NOT_EQUAL; } else if ( (v = strstr(pair, "=")) ) { *v++ = '\0'; op = AUDIT_EQUAL; } else { return -EAU_OPEQNOTEQ; } if (*f == 0) return -EAU_COMPFIELDNAME; if (*v == 0) return -EAU_COMPVAL; if ((field1 = audit_name_to_field(f)) < 0) return -EAU_COMPFIELDUNKNOWN; if ((field2 = audit_name_to_field(v)) < 0) return -EAU_COMPVALUNKNOWN; /* Interfield comparison can only be in exit filter */ if (flags != AUDIT_FILTER_EXIT) return -EAU_EXITONLY; // It should always be AUDIT_FIELD_COMPARE rule->fields[rule->field_count] = AUDIT_FIELD_COMPARE; rule->fieldflags[rule->field_count] = op; /* oh god, so many permutations */ switch (field1) { /* UID comparison */ case AUDIT_EUID: switch(field2) { case AUDIT_LOGINUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_EUID; break; case AUDIT_FSUID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_FSUID; break; case AUDIT_OBJ_UID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_OBJ_UID; break; case AUDIT_SUID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_SUID; break; case AUDIT_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_FSUID: switch(field2) { case AUDIT_LOGINUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_FSUID; break; case AUDIT_EUID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_FSUID; break; case AUDIT_OBJ_UID: rule->values[rule->field_count] = AUDIT_COMPARE_FSUID_TO_OBJ_UID; break; case AUDIT_SUID: rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_FSUID; break; case AUDIT_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_FSUID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_LOGINUID: switch(field2) { case AUDIT_EUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_EUID; break; case AUDIT_FSUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_FSUID; break; case AUDIT_OBJ_UID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_OBJ_UID; break; case AUDIT_SUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_SUID; break; case AUDIT_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_AUID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_SUID: switch(field2) { case AUDIT_LOGINUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_SUID; break; case AUDIT_EUID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_SUID; break; case AUDIT_FSUID: rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_FSUID; break; case AUDIT_OBJ_UID: rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_OBJ_UID; break; case AUDIT_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_SUID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_OBJ_UID: switch(field2) { case AUDIT_LOGINUID: rule->values[rule->field_count] = AUDIT_COMPARE_AUID_TO_OBJ_UID; break; case AUDIT_EUID: rule->values[rule->field_count] = AUDIT_COMPARE_EUID_TO_OBJ_UID; break; case AUDIT_FSUID: rule->values[rule->field_count] = AUDIT_COMPARE_FSUID_TO_OBJ_UID; break; case AUDIT_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID; break; case AUDIT_SUID: rule->values[rule->field_count] = AUDIT_COMPARE_SUID_TO_OBJ_UID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_UID: switch(field2) { case AUDIT_LOGINUID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_AUID; break; case AUDIT_EUID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_EUID; break; case AUDIT_FSUID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_FSUID; break; case AUDIT_OBJ_UID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_OBJ_UID; break; case AUDIT_SUID: rule->values[rule->field_count] = AUDIT_COMPARE_UID_TO_SUID; break; default: return -EAU_COMPINCOMPAT; } break; /* GID comparisons */ case AUDIT_EGID: switch(field2) { case AUDIT_FSGID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_FSGID; break; case AUDIT_GID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID; break; case AUDIT_OBJ_GID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_OBJ_GID; break; case AUDIT_SGID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_SGID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_FSGID: switch(field2) { case AUDIT_SGID: rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_FSGID; break; case AUDIT_GID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_FSGID; break; case AUDIT_OBJ_GID: rule->values[rule->field_count] = AUDIT_COMPARE_FSGID_TO_OBJ_GID; break; case AUDIT_EGID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_FSGID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_GID: switch(field2) { case AUDIT_EGID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_EGID; break; case AUDIT_FSGID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_FSGID; break; case AUDIT_OBJ_GID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID; break; case AUDIT_SGID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_SGID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_OBJ_GID: switch(field2) { case AUDIT_EGID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_OBJ_GID; break; case AUDIT_FSGID: rule->values[rule->field_count] = AUDIT_COMPARE_FSGID_TO_OBJ_GID; break; case AUDIT_GID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_OBJ_GID; break; case AUDIT_SGID: rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_OBJ_GID; break; default: return -EAU_COMPINCOMPAT; } break; case AUDIT_SGID: switch(field2) { case AUDIT_FSGID: rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_FSGID; break; case AUDIT_GID: rule->values[rule->field_count] = AUDIT_COMPARE_GID_TO_SGID; break; case AUDIT_OBJ_GID: rule->values[rule->field_count] = AUDIT_COMPARE_SGID_TO_OBJ_GID; break; case AUDIT_EGID: rule->values[rule->field_count] = AUDIT_COMPARE_EGID_TO_SGID; break; default: return -EAU_COMPINCOMPAT; } break; default: return -EAU_COMPINCOMPAT; break; } rule->field_count++; return 0; } int audit_determine_machine(const char *arch) { // What do we want? i686, x86_64 or b64, b32 int machine; unsigned int bits = 0; if (strcasecmp("b64", arch) == 0) { bits = __AUDIT_ARCH_64BIT; machine = audit_detect_machine(); } else if (strcasecmp("b32", arch) == 0) { bits = ~__AUDIT_ARCH_64BIT; machine = audit_detect_machine(); } else { machine = audit_name_to_machine(arch); if (machine < 0) { // See if its numeric unsigned int ival; errno = 0; ival = strtoul(arch, NULL, 16); if (errno) return -4; machine = audit_elf_to_machine(ival); } } if (machine < 0) return -4; /* Here's where we fixup the machine. For example, they give * x86_64 & want 32 bits we translate that to i686. */ if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_86_64) machine = MACH_X86; else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_PPC64) machine = MACH_PPC; else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_S390X) machine = MACH_S390; else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_AARCH64) machine = MACH_ARM; else if (bits == ~__AUDIT_ARCH_64BIT && machine == MACH_RISCV64) machine = MACH_RISCV32; /* Check for errors - return -6 * We don't allow 32 bit machines to specify 64 bit. */ switch (machine) { case MACH_X86: if (bits == __AUDIT_ARCH_64BIT) return -6; break; case MACH_PPC: if (bits == __AUDIT_ARCH_64BIT) return -6; break; case MACH_S390: if (bits == __AUDIT_ARCH_64BIT) return -6; break; #ifdef WITH_ARM case MACH_ARM: if (bits == __AUDIT_ARCH_64BIT) return -6; /* 32 bit only */ break; #endif #ifdef WITH_AARCH64 case MACH_AARCH64: if (bits && bits != __AUDIT_ARCH_64BIT) return -6; /* 64 bit only */ break; #endif #ifdef WITH_RISCV case MACH_RISCV32: if (bits == __AUDIT_ARCH_64BIT) return -6; break; #endif case MACH_86_64: /* fallthrough */ case MACH_PPC64: /* fallthrough */ case MACH_S390X: /* fallthrough */ case MACH_IO_URING: case MACH_RISCV64: /* fallthrough */ break; case MACH_PPC64LE: /* 64 bit only */ if (bits && bits != __AUDIT_ARCH_64BIT) return -6; break; default: return -6; } return machine; } int _audit_parse_syscall(const char *optarg, struct audit_rule_data *rule) { int retval = 0; char *saved; if (strchr(optarg, ',')) { char *ptr, *tmp = strdup(optarg); if (tmp == NULL) return -1; ptr = strtok_r(tmp, ",", &saved); while (ptr) { retval = audit_rule_syscallbyname_data(rule, ptr); if (retval != 0) { if (retval == -1) { audit_msg(LOG_ERR, "Syscall name unknown: %s", ptr); retval = -3; // error reported } break; } ptr = strtok_r(NULL, ",", &saved); } free(tmp); return retval; } return audit_rule_syscallbyname_data(rule, optarg); } /* * Filters unsupported syscalls from a comma-separated string based * on the given architecture. Returns a new string with supported syscalls * or NULL on error. */ static char* filter_supported_syscalls(const char* syscalls, int machine) { if (syscalls == NULL) { return NULL; } char buf[512] = ""; char* ptr = buf; const char* delimiter = ","; char* syscalls_copy = strdup(syscalls); if (syscalls_copy == NULL) return NULL; char* token = strtok(syscalls_copy, delimiter); int first = 1; // Track if this is the first syscall being added while (token != NULL) { if (audit_name_to_syscall(token, machine) != -1) { if (!first) *ptr++ = ','; ptr = stpcpy(ptr, token); first = 0; } token = strtok(NULL, delimiter); } free(syscalls_copy); // If no valid syscalls were found, return NULL if (ptr == buf) { return NULL; } return strdup(buf); } static int audit_add_perm_syscalls(int perm, struct audit_rule_data *rule) { // We only get here if syscall notation is being used in the rule. // The -w -p -k options are handled in auditctl itself. See // audit_setup_watch_name and audit_setup_perms. Therefore if no // arch declared, we leave the old behavior for backwards compatibility // and just warn about performance. if (_audit_elf == 0) { audit_msg(LOG_INFO, "perm used without an arch is slower"); return 0; } const int machine = audit_elf_to_machine(_audit_elf); const char *syscalls = audit_perm_to_name(perm); const char *syscalls_to_use; // The permtab table is hardcoded, but some syscalls, like rename // on arm64, are unavailable on certain architectures. To ensure compatibility, // we must avoid creating rules with unsupported syscalls. char* filtered_syscalls = filter_supported_syscalls(syscalls, machine); if (filtered_syscalls == NULL) { // use original syscalls in case we failed to parse - should not happen syscalls_to_use = syscalls; audit_msg(LOG_WARNING, "Filtering syscalls failed; using original syscalls."); } else { syscalls_to_use = filtered_syscalls; } int rc = _audit_parse_syscall(syscalls_to_use, rule); switch (rc) { case 0: _audit_syscalladded = 1; break; case -1: // Should never happen audit_msg(LOG_ERR, "Syscall name unknown: %s", syscalls_to_use); break; default: // Error reported - do nothing here break; } free(filtered_syscalls); return rc; } int audit_rule_fieldpair_data(struct audit_rule_data **rulep, char *pair, int flags) { char *f = pair; char *v; int op; int field; int vlen; int offset; struct audit_rule_data *rule = *rulep, *tmp; if (f == NULL) return -EAU_FILTERMISSING; if (rule->field_count >= (AUDIT_MAX_FIELDS - 1)) return -EAU_FIELDTOOMANY; /* look for 2-char operators first then look for 1-char operators afterwards when found, null out the bytes under the operators to split and set value pointer just past operator bytes */ if ( (v = strstr(pair, "!=")) ) { *v++ = '\0'; *v++ = '\0'; op = AUDIT_NOT_EQUAL; } else if ( (v = strstr(pair, ">=")) ) { *v++ = '\0'; *v++ = '\0'; op = AUDIT_GREATER_THAN_OR_EQUAL; } else if ( (v = strstr(pair, "<=")) ) { *v++ = '\0'; *v++ = '\0'; op = AUDIT_LESS_THAN_OR_EQUAL; } else if ( (v = strstr(pair, "&=")) ) { *v++ = '\0'; *v++ = '\0'; op = AUDIT_BIT_TEST; } else if ( (v = strstr(pair, "=")) ) { *v++ = '\0'; op = AUDIT_EQUAL; } else if ( (v = strstr(pair, ">")) ) { *v++ = '\0'; op = AUDIT_GREATER_THAN; } else if ( (v = strstr(pair, "<")) ) { *v++ = '\0'; op = AUDIT_LESS_THAN; } else if ( (v = strstr(pair, "&")) ) { *v++ = '\0'; op = AUDIT_BIT_MASK; } if (v == NULL) return -EAU_OPMISSING; if (*f == 0) return -EAU_FIELDNAME; if (*v == 0) return -EAU_FIELDVALMISSING; if ((field = audit_name_to_field(f)) < 0) return -EAU_FIELDUNKNOWN; /* Exclude filter can be used only with MSGTYPE, cred, and EXE fields * when the EXTEND Feature is not present. */ if (flags == AUDIT_FILTER_EXCLUDE) { uint32_t features = audit_get_features(); if ((features & AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND) == 0) { switch(field) { case AUDIT_PID: case AUDIT_UID: case AUDIT_GID: case AUDIT_LOGINUID: case AUDIT_MSGTYPE: case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_EXE: break; default: return -EAU_MSGTYPECREDEXCLUDE; } } } /* FS filter can be used only with FSTYPE field */ if (flags == AUDIT_FILTER_FS) { uint32_t features = audit_get_features(); if ((features & AUDIT_FEATURE_BITMAP_FILTER_FS) == 0) { return -EAU_FILTERNOSUPPORT; } } rule->fields[rule->field_count] = field; rule->fieldflags[rule->field_count] = op; switch (field) { case AUDIT_UID: case AUDIT_EUID: case AUDIT_SUID: case AUDIT_FSUID: case AUDIT_LOGINUID: case AUDIT_OBJ_UID: // Do positive & negative separate for 32 bit systems vlen = strlen(v); if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtoul(v, NULL, 0); else if (vlen >= 2 && *(v)=='-' && (isdigit((unsigned char)*(v+1)))) rule->values[rule->field_count] = strtol(v, NULL, 0); else { if (strcmp(v, "unset") == 0) rule->values[rule->field_count] = 4294967295; else if (audit_name_to_uid(v, &rule->values[rule->field_count])) { audit_msg(LOG_ERR, "Unknown user: %s", v); return -EAU_PRINT_NOTHING; } } break; case AUDIT_GID: case AUDIT_EGID: case AUDIT_SGID: case AUDIT_FSGID: case AUDIT_OBJ_GID: if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtol(v, NULL, 0); else { if (audit_name_to_gid(v, &rule->values[rule->field_count])) { audit_msg(LOG_ERR, "Unknown group: %s", v); return -EAU_PRINT_NOTHING; } } break; case AUDIT_EXIT: if (flags != AUDIT_FILTER_EXIT) return -EAU_EXITONLY; vlen = strlen(v); if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtol(v, NULL, 0); else if (vlen >= 2 && *(v)=='-' && (isdigit((unsigned char)*(v+1)))) rule->values[rule->field_count] = strtol(v, NULL, 0); else { rule->values[rule->field_count] = audit_name_to_errno(v); if (rule->values[rule->field_count] == 0) return -EAU_ERRUNKNOWN; } break; case AUDIT_MSGTYPE: if (flags != AUDIT_FILTER_EXCLUDE && flags != AUDIT_FILTER_USER) return -EAU_MSGTYPEEXCLUDEUSER; if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtol(v, NULL, 0); else if (audit_name_to_msg_type(v) > 0) rule->values[rule->field_count] = audit_name_to_msg_type(v); else return -EAU_MSGTYPEUNKNOWN; break; /* These next few are strings */ case AUDIT_OBJ_USER: case AUDIT_OBJ_ROLE: case AUDIT_OBJ_TYPE: case AUDIT_OBJ_LEV_LOW: case AUDIT_OBJ_LEV_HIGH: case AUDIT_WATCH: case AUDIT_DIR: /* Watch & object filtering is invalid on anything * but exit */ if (flags != AUDIT_FILTER_EXIT) return -EAU_EXITONLY; if (field == AUDIT_WATCH || field == AUDIT_DIR) _audit_permadded = 1; /* fallthrough */ case AUDIT_SUBJ_USER: case AUDIT_SUBJ_ROLE: case AUDIT_SUBJ_TYPE: case AUDIT_SUBJ_SEN: case AUDIT_SUBJ_CLR: case AUDIT_FILTERKEY: case AUDIT_EXE: if (field == AUDIT_EXE) { uint32_t features = audit_get_features(); if ((features & AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH) == 0) return -EAU_FIELDNOSUPPORT; if (!(op == AUDIT_NOT_EQUAL || op == AUDIT_EQUAL)) return -EAU_OPEQNOTEQ; _audit_exeadded = 1; } if (field == AUDIT_FILTERKEY && !(_audit_syscalladded || _audit_permadded || _audit_exeadded || _audit_filterfsadded)) return -EAU_KEYDEP; vlen = strlen(v); if (field == AUDIT_FILTERKEY && vlen > AUDIT_MAX_KEY_LEN) return -EAU_STRTOOLONG; else if (vlen > PATH_MAX) return -EAU_STRTOOLONG; rule->values[rule->field_count] = vlen; offset = rule->buflen; rule->buflen += vlen; tmp = realloc(rule, sizeof(*rule) + rule->buflen); if (tmp == NULL) { free(rule); audit_msg(LOG_ERR, "Cannot realloc memory!"); return -3; } *rulep = tmp; rule = tmp; strncpy(&rule->buf[offset], v, vlen); break; case AUDIT_ARCH: if (_audit_syscalladded) return -EAU_ARCHMISPLACED; if (!(op == AUDIT_NOT_EQUAL || op == AUDIT_EQUAL)) return -EAU_OPEQNOTEQ; if (isdigit((unsigned char)*(v))) { int machine; errno = 0; _audit_elf = strtoul(v, NULL, 0); if (errno) return -EAU_ELFUNKNOWN; // Make sure we have a valid mapping machine = audit_elf_to_machine(_audit_elf); if (machine < 0) return -EAU_ELFUNKNOWN; } else { const char *arch=v; unsigned int machine, elf; machine = audit_determine_machine(arch); /* OK, we have the machine type, now convert to elf. */ elf = audit_machine_to_elf(machine); if (elf == 0) return -EAU_ELFUNKNOWN; _audit_elf = elf; } rule->values[rule->field_count] = _audit_elf; _audit_archadded = 1; break; case AUDIT_PERM: if (!(flags == AUDIT_FILTER_EXIT || flags == AUDIT_FILTER_EXCLUDE)) return -EAU_EXITONLY; else if (op != AUDIT_EQUAL) return -EAU_OPEQ; else { unsigned int i, len, val = 0; int rc; len = strlen(v); if (len > 4) return -EAU_STRTOOLONG; for (i = 0; i < len; i++) { switch (tolower((unsigned char)v[i])) { case 'r': val |= AUDIT_PERM_READ; rc=audit_add_perm_syscalls(AUDIT_PERM_READ,rule); break; case 'w': val |= AUDIT_PERM_WRITE; rc=audit_add_perm_syscalls(AUDIT_PERM_WRITE,rule); break; case 'x': val |= AUDIT_PERM_EXEC; rc=audit_add_perm_syscalls(AUDIT_PERM_EXEC,rule); break; case 'a': val |= AUDIT_PERM_ATTR; rc=audit_add_perm_syscalls(AUDIT_PERM_ATTR,rule); break; default: return -EAU_PERMRWXA; } if (rc) return -EAU_PERM_SYSCALL; } rule->values[rule->field_count] = val; } break; case AUDIT_FILETYPE: if (!(flags == AUDIT_FILTER_EXIT)) return -EAU_EXITONLY; rule->values[rule->field_count] = audit_name_to_ftype(v); if ((int)rule->values[rule->field_count] < 0) { return -EAU_FILETYPEUNKNOWN; } break; case AUDIT_FSTYPE: if (!(flags == AUDIT_FILTER_FS)) return -EAU_FIELDUNAVAIL; if (!(op == AUDIT_NOT_EQUAL || op == AUDIT_EQUAL)) return -EAU_OPEQNOTEQ; if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtoul(v, NULL, 0); else rule->values[rule->field_count] = audit_name_to_fstype(v); if ((int)rule->values[rule->field_count] == -1) { return -EAU_FSTYPEUNKNOWN; } _audit_filterfsadded = 1; break; case AUDIT_ARG0...AUDIT_ARG3: vlen = strlen(v); if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtoul(v, NULL, 0); else if (vlen >= 2 && *(v)=='-' && (isdigit((unsigned char)*(v+1)))) rule->values[rule->field_count] = strtol(v, NULL, 0); else return -EAU_FIELDVALNUM; break; case AUDIT_SESSIONID: if ((audit_get_features() & AUDIT_FEATURE_BITMAP_SESSIONID_FILTER) == 0) return -EAU_FIELDNOSUPPORT; if (flags != AUDIT_FILTER_EXCLUDE && flags != AUDIT_FILTER_USER && flags != AUDIT_FILTER_EXIT) return -EAU_FIELDNOFILTER; // Do positive & negative separate for 32 bit systems vlen = strlen(v); if (isdigit((unsigned char)*(v))) rule->values[rule->field_count] = strtoul(v, NULL, 0); else if (vlen >= 2 && *(v)=='-' && (isdigit((unsigned char)*(v+1)))) rule->values[rule->field_count] = strtol(v, NULL, 0); else if (strcmp(v, "unset") == 0) rule->values[rule->field_count] = 4294967295; break; case AUDIT_SADDR_FAM: rule->values[rule->field_count] = strtoul(v, NULL, 0); if (rule->values[rule->field_count] >= AF_MAX) return -EAU_FIELDVALTOOBIG; break; case AUDIT_DEVMAJOR...AUDIT_INODE: case AUDIT_SUCCESS: if (flags != AUDIT_FILTER_EXIT) return -EAU_EXITONLY; /* fallthrough */ default: if (field == AUDIT_INODE) { if (!(op == AUDIT_NOT_EQUAL || op == AUDIT_EQUAL)) return -EAU_OPEQNOTEQ; } if (field == AUDIT_PPID && !(flags==AUDIT_FILTER_EXIT)) return -EAU_EXITONLY; if (!isdigit((unsigned char)*(v))) return -EAU_FIELDVALNUM; if (field == AUDIT_INODE) rule->values[rule->field_count] = strtoul(v, NULL, 0); else rule->values[rule->field_count] = strtol(v, NULL, 0); break; } rule->field_count++; return 0; } struct audit_rule_data *audit_rule_create_data(void) { struct audit_rule_data *rule; rule = malloc(sizeof(*rule)); if (rule != NULL) { audit_rule_init_data(rule); } return rule; } void audit_rule_init_data(struct audit_rule_data *rule) { memset(rule, 0, sizeof(*rule)); } void audit_rule_free_data(struct audit_rule_data *rule) { free(rule); } static void memset_secure(void *buf, size_t size) { buf = memset(buf, '\0', size); __asm__ __volatile__ ("" : : "r"(buf) : "memory"); } // This use is OK because its creating rules for the local // machine and is looking up a local user. static int audit_name_to_uid(const char *name, uid_t *uid) { struct passwd pwd; struct passwd *result; char *buf; long bufsize; int rc; bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); if (bufsize <= 0) bufsize = 1024; retry: buf = malloc(bufsize); if (!buf) return 1; errno = 0; rc = getpwnam_r(name, &pwd, buf, bufsize, &result); if (rc == ERANGE) { free(buf); if (__builtin_mul_overflow(bufsize, 2, &bufsize)) { errno = ENOMEM; return 1; } goto retry; } if (result == NULL) { free(buf); /* getpwnam() might return ECONNREFUSED in some very * specific cases when using LDAP. * Manually set it to ENOENT so callers don't get confused * with netlink's ECONNREFUSED */ if (errno == ECONNREFUSED) errno = ENOENT; return 1; } *uid = result->pw_uid; memset_secure(buf, bufsize); free(buf); return 0; } static int audit_name_to_gid(const char *name, gid_t *gid) { struct group gr; struct group *result; char *buf; long bufsize; int rc; bufsize = sysconf(_SC_GETGR_R_SIZE_MAX); if (bufsize <= 0) bufsize = 1024; retry: buf = malloc(bufsize); if (!buf) return 1; errno = 0; rc = getgrnam_r(name, &gr, buf, bufsize, &result); if (rc == ERANGE) { free(buf); if (__builtin_mul_overflow(bufsize, 2, &bufsize)) { errno = ENOMEM; return 1; } goto retry; } if (result == NULL) { free(buf); /* See above for explanation. */ if (errno == ECONNREFUSED) errno = ENOENT; return 1; } *gid = result->gr_gid; memset_secure(buf, bufsize); free(buf); return 0; } int audit_detect_machine(void) { struct utsname uts; if (uname(&uts) == 0) // strcpy(uts.machine, "x86_64"); return audit_name_to_machine(uts.machine); return -1; } #ifndef NO_TABLES void audit_number_to_errmsg(int errnumber, const char *opt) { unsigned int i; for (i = 0; i < sizeof(err_msgtab)/sizeof(struct msg_tab); i++) { if (err_msgtab[i].key == errnumber) { switch (err_msgtab[i].position) { case 0: fprintf(stderr, "%s\n", err_msgtab[i].cvalue); break; case 1: fprintf(stderr, "%s %s\n", opt, err_msgtab[i].cvalue); break; case 2: fprintf(stderr, "%s %s\n", err_msgtab[i].cvalue, opt); break; default: break; } return; } } } #endif int audit_can_control(void) { #ifdef HAVE_LIBCAP_NG void *state = capng_save_state(); int rc = capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_CONTROL); capng_restore_state(&state); return rc; #else return (geteuid() == 0); #endif } int audit_can_write(void) { #ifdef HAVE_LIBCAP_NG void *state = capng_save_state(); int rc = capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_WRITE); capng_restore_state(&state); return rc; #else return (geteuid() == 0); #endif } int audit_can_read(void) { #if defined ( HAVE_LIBCAP_NG ) && ( CAP_AUDIT_READ ) void *state = capng_save_state(); int rc = capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_READ); capng_restore_state(&state); return rc; #else return (geteuid() == 0); #endif } audit-userspace-4.0.5/lib/libaudit.h000066400000000000000000000241431501761310600173360ustar00rootroot00000000000000/* libaudit.h -- * Copyright 2004-2018,2021-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith */ #ifndef _LIBAUDIT_H_ #define _LIBAUDIT_H_ #include #include #include #include #include #include #include // The following macros originate in sys/cdefs.h // gcc-analyzer notation // Define buffer access modes #ifndef __attr_access # define __attr_access(x) #endif // Warn unused result #ifndef __wur # define __wur #endif #include #ifdef __cplusplus extern "C" { #endif /* Audit message type classification of the 5.0 kernel: * 1000 - 1099 are for commanding the audit system * 1100 - 1199 user space trusted application messages * 1200 - 1299 messages internal to the audit daemon * 1300 - 1399 audit event messages * 1400 - 1499 kernel SE Linux use * 1500 - 1599 AppArmor events * 1600 - 1699 kernel crypto events * 1700 - 1799 kernel anomaly records * 1800 - 1899 kernel integrity labels and related events * 1800 - 1999 future kernel use * 2001 - 2099 unused (kernel) * 2100 - 2199 user space anomaly records * 2200 - 2299 user space actions taken in response to anomalies * 2300 - 2399 user space generated LSPP events * 2400 - 2499 user space crypto events * 2500 - 2599 user space virtualization management events * 2600 - 2999 future user space (maybe integrity labels and related events) * * * NOTE: as of the audit-4.0 release, all of the audit record type * definitions have moved to the audit-records.h header file * */ /* This is related to the filterkey patch */ #define AUDIT_KEY_SEPARATOR 0x01 /* These are used in filter control */ #ifndef AUDIT_FILTER_URING_EXIT #define AUDIT_FILTER_URING_EXIT 0x07 /* Apply rule at io_uring op exit */ #endif #ifndef AUDIT_FILTER_EXCLUDE #define AUDIT_FILTER_EXCLUDE AUDIT_FILTER_TYPE #endif #define AUDIT_FILTER_MASK 0x07 /* Mask to get actual filter */ #define AUDIT_FILTER_UNSET 0x80 /* This value means filter is unset */ /* This is the character that separates event data from enrichment fields */ #define AUDIT_INTERP_SEPARATOR 0x1D ////////////////////////////////////////////////////// // This is an external ABI. Any changes in here will // likely affect pam_loginuid. There might be other // apps that use this low level interface, but I don't // know of any. // /* data structure for who signaled the audit daemon */ struct audit_sig_info { uid_t uid; pid_t pid; char ctx[0]; }; /* defines for audit subsystem */ #define MAX_AUDIT_MESSAGE_LENGTH 8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1 struct audit_message { struct nlmsghdr nlh; char data[MAX_AUDIT_MESSAGE_LENGTH]; }; // internal - forward declaration struct daemon_conf; struct audit_reply { int type; int len; struct nlmsghdr *nlh; struct audit_message msg; /* Using a union to compress this structure since only one of * the following should be valid for any packet. */ union { struct audit_status *status; struct audit_rule_data *ruledata; struct audit_login *login; char *message; struct nlmsgerr *error; struct audit_sig_info *signal_info; struct daemon_conf *conf; #ifdef AUDIT_FEATURE_VERSION struct audit_features *features; #endif }; }; // // End of ABI control ////////////////////////////////////////////////////// ////////////////////////////////////////////////////// // audit dispatcher interface // /* audit_dispatcher_header: This header is versioned. If anything gets * added to it, it must go at the end and the version number bumped. * This MUST BE fixed size for compatibility. If you are going to add * new member then add them into _structure_ part. */ struct audit_dispatcher_header { uint32_t ver; /* The version of this protocol */ uint32_t hlen; /* Header length */ uint32_t type; /* Message type */ uint32_t size; /* Size of data following the header */ }; // Original protocol starts with msg=' #define AUDISP_PROTOCOL_VER 0 // Starts with node and/or type already in the text before msg= // IOW, its preformatted in the audit daemon. #define AUDISP_PROTOCOL_VER2 1 /////////////////////////////////////////////////// // Libaudit API // /* This is the machine type list */ typedef enum { MACH_X86=0, MACH_86_64, MACH_IA64, // Deprecated but has to stay MACH_PPC64, MACH_PPC, MACH_S390X, MACH_S390, MACH_ALPHA, // Deprecated but has to stay MACH_ARM, MACH_AARCH64, MACH_PPC64LE, MACH_IO_URING, MACH_RISCV32, MACH_RISCV64 } machine_t; /* These are the valid audit failure tunable enum values */ typedef enum { FAIL_IGNORE=0, FAIL_LOG, FAIL_TERMINATE } auditfail_t; /* Messages */ typedef enum { MSG_STDERR, MSG_SYSLOG, MSG_QUIET } message_t; typedef enum { DBG_NO, DBG_YES } debug_message_t; void set_aumessage_mode(message_t mode, debug_message_t debug); /* General */ typedef enum { GET_REPLY_BLOCKING=0, GET_REPLY_NONBLOCKING } reply_t; int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek) __wur; uid_t audit_getloginuid(void); int audit_setloginuid(uid_t uid) __wur; uint32_t audit_get_session(void); int audit_detect_machine(void); int audit_determine_machine(const char *arch); char *audit_format_signal_info(char *buf, int len, const char *op, const struct audit_reply *rep, const char *res) __attr_access ((__write_only__, 1, 2)); /* Translation functions */ int audit_name_to_field(const char *field); const char *audit_field_to_name(int field); int audit_name_to_syscall(const char *sc, int machine); const char *audit_syscall_to_name(int sc, int machine); const char *audit_uringop_to_name(int uringop); int audit_name_to_uringop(const char *uringop); int audit_name_to_flag(const char *flag); const char *audit_flag_to_name(int flag); int audit_name_to_action(const char *action); const char *audit_action_to_name(int action); int audit_name_to_msg_type(const char *msg_type); const char *audit_msg_type_to_name(int msg_type); int audit_name_to_machine(const char *machine); const char *audit_machine_to_name(int machine); unsigned int audit_machine_to_elf(int machine); int audit_elf_to_machine(unsigned int elf); const char *audit_operator_to_symbol(int op); int audit_name_to_errno(const char *error); const char *audit_errno_to_name(int error); int audit_name_to_ftype(const char *name); const char *audit_ftype_to_name(int ftype); int audit_name_to_fstype(const char *name); const char *audit_fstype_to_name(int fstype); void audit_number_to_errmsg(int errnumber, const char *opt); /* AUDIT_GET */ int audit_request_status(int fd); int audit_is_enabled(int fd); int get_auditfail_action(auditfail_t *failmode); int audit_request_features(int fd); uint32_t audit_get_features(void); /* AUDIT_SET */ typedef enum { WAIT_NO, WAIT_YES } rep_wait_t; int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) __wur; int audit_set_enabled(int fd, uint32_t enabled) __wur; int audit_set_failure(int fd, uint32_t failure) __wur; int audit_set_rate_limit(int fd, uint32_t limit); int audit_set_backlog_limit(int fd, uint32_t limit); int audit_set_backlog_wait_time(int fd, uint32_t bwt); int audit_reset_lost(int fd); int audit_reset_backlog_wait_time_actual(int fd); int audit_set_feature(int fd, unsigned feature, unsigned value, unsigned lock) __wur; int audit_set_loginuid_immutable(int fd) __wur; /* AUDIT_LIST_RULES */ int audit_request_rules_list_data(int fd); /* SIGNAL_INFO */ int audit_request_signal_info(int fd); /* AUDIT_WATCH */ int audit_update_watch_perms(struct audit_rule_data *rule, int perms); int audit_add_watch(struct audit_rule_data **rulep, const char *path); int audit_add_watch_dir(int type, struct audit_rule_data **rulep, const char *path); int audit_trim_subtrees(int fd); int audit_make_equivalent(int fd, const char *mount_point, const char *subtree); /* AUDIT_ADD_RULE */ int audit_add_rule_data(int fd, struct audit_rule_data *rule, int flags, int action); /* AUDIT_DEL_RULE */ int audit_delete_rule_data(int fd, struct audit_rule_data *rule, int flags, int action); /* Rule-building helper functions */ /* Heap-allocates and initializes an audit_rule_data */ struct audit_rule_data *audit_rule_create_data(void); /* Initializes an existing audit_rule_data struct */ void audit_rule_init_data(struct audit_rule_data *rule); int audit_rule_syscallbyname_data(struct audit_rule_data *rule, const char *scall); int audit_rule_io_uringbyname_data(struct audit_rule_data *rule, const char *scall); /* Note that the following function takes a **, where audit_rule_fieldpair() * takes just a *. That structure may need to be reallocated as a result of * adding new fields */ int audit_rule_fieldpair_data(struct audit_rule_data **rulep, char *pair, int flags); int audit_rule_interfield_comp_data(struct audit_rule_data **rulep, char *pair, int flags); /* Deallocates the audit_rule_rule object, and any associated resources */ void audit_rule_free_data(struct audit_rule_data *rule); /* Capability testing functions */ int audit_can_control(void); int audit_can_write(void); int audit_can_read(void); #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/lib/lookup_table.c000066400000000000000000000201351501761310600202110ustar00rootroot00000000000000/* lookup_table.c -- * Copyright 2004-2008,2012-13,2016,2023 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith */ #include "config.h" #include #include #include #include #include #include #include // This code is at the center of many performance issues. The following // ensure that it is optimized the most without making all of the audit // subsystem bigger. #pragma GCC optimize("O3") #pragma GCC optimize("-funroll-loops") #include "libaudit.h" #include "gen_tables.h" #include "private.h" #ifndef NO_TABLES #ifdef WITH_ARM #include "arm_tables.h" #endif #ifdef WITH_AARCH64 #include "aarch64_tables.h" #endif #ifdef WITH_RISCV #include "riscv64_tables.h" #include "riscv32_tables.h" #endif #include "i386_tables.h" #include "ppc_tables.h" #include "s390_tables.h" #include "s390x_tables.h" #include "x86_64_tables.h" #ifdef WITH_IO_URING #include "uringop_tables.h" #endif #include "errtabs.h" #include "fstypetabs.h" #include "ftypetabs.h" #include "fieldtabs.h" #include "permtabs.h" #endif #include "msg_typetabs.h" #include "actiontabs.h" #include "flagtabs.h" #include "machinetabs.h" #include "optabs.h" struct int_transtab { int key; unsigned int lvalue; }; static const struct int_transtab elftab[] = { { MACH_X86, AUDIT_ARCH_I386 }, { MACH_86_64, AUDIT_ARCH_X86_64 }, { MACH_PPC64, AUDIT_ARCH_PPC64 }, { MACH_PPC64LE, AUDIT_ARCH_PPC64LE}, { MACH_PPC, AUDIT_ARCH_PPC }, { MACH_S390X, AUDIT_ARCH_S390X }, { MACH_S390, AUDIT_ARCH_S390 }, #ifdef WITH_ARM { MACH_ARM, AUDIT_ARCH_ARM }, #endif #ifdef WITH_AARCH64 { MACH_AARCH64, AUDIT_ARCH_AARCH64}, #endif #ifdef WITH_RISCV { MACH_RISCV32, AUDIT_ARCH_RISCV32 }, { MACH_RISCV64, AUDIT_ARCH_RISCV64 }, #endif }; #define AUDIT_ELF_NAMES (sizeof(elftab)/sizeof(elftab[0])) int audit_name_to_field(const char *field) { #ifndef NO_TABLES int res; if (field_s2i(field, &res) != 0) return res; #endif return -1; } const char *audit_field_to_name(int field) { #ifndef NO_TABLES return field_i2s(field); #else return NULL; #endif } int audit_name_to_uringop(const char *uringop) { #ifdef WITH_IO_URING int res = -1, found = 0; #ifndef NO_TABLES found = uringop_s2i(uringop, &res); #endif if (found) return res; #endif return -1; } int audit_name_to_syscall(const char *sc, int machine) { int res = -1, found = 0; switch (machine) { #ifndef NO_TABLES case MACH_X86: found = i386_syscall_s2i(sc, &res); break; case MACH_86_64: found = x86_64_syscall_s2i(sc, &res); break; case MACH_PPC64: case MACH_PPC64LE: case MACH_PPC: found = ppc_syscall_s2i(sc, &res); break; case MACH_S390X: found = s390x_syscall_s2i(sc, &res); break; case MACH_S390: found = s390_syscall_s2i(sc, &res); break; #ifdef WITH_ARM case MACH_ARM: found = arm_syscall_s2i(sc, &res); break; #endif #ifdef WITH_AARCH64 case MACH_AARCH64: found = aarch64_syscall_s2i(sc, &res); break; #endif #ifdef WITH_RISCV case MACH_RISCV64: found = riscv64_syscall_s2i(sc, &res); break; case MACH_RISCV32: found = riscv32_syscall_s2i(sc, &res); break; #endif #endif case MACH_IO_URING: return audit_name_to_uringop(sc); break; default: return -1; } if (found) return res; return -1; } const char *audit_uringop_to_name(int uringop) { #ifdef WITH_IO_URING #ifndef NO_TABLES return uringop_i2s(uringop); #endif #endif return NULL; } const char *audit_syscall_to_name(int sc, int machine) { #ifndef NO_TABLES switch (machine) { case MACH_X86: return i386_syscall_i2s(sc); case MACH_86_64: return x86_64_syscall_i2s(sc); case MACH_PPC64: case MACH_PPC64LE: case MACH_PPC: return ppc_syscall_i2s(sc); case MACH_S390X: return s390x_syscall_i2s(sc); case MACH_S390: return s390_syscall_i2s(sc); #ifdef WITH_ARM case MACH_ARM: return arm_syscall_i2s(sc); #endif #ifdef WITH_AARCH64 case MACH_AARCH64: return aarch64_syscall_i2s(sc); #endif #ifdef WITH_RISCV case MACH_RISCV64: return riscv64_syscall_i2s(sc); case MACH_RISCV32: return riscv32_syscall_i2s(sc); #endif case MACH_IO_URING: return audit_uringop_to_name(sc); } #endif return NULL; } int audit_name_to_flag(const char *flag) { int res; if (flag_s2i(flag, &res) != 0) return res; return -1; } const char *audit_flag_to_name(int flag) { return flag_i2s(flag); } int audit_name_to_action(const char *action) { int res; if (action_s2i(action, &res) != 0) return res; return -1; } const char *audit_action_to_name(int action) { return action_i2s(action); } // On the critical path for ausearch parser int audit_name_to_msg_type(const char *msg_type) { int rc; if (msg_type_s2i(msg_type, &rc) != 0) return rc; /* Take a stab at converting */ if (strncmp(msg_type, "UNKNOWN[", 8) == 0) { int len; char buf[8]; const char *end = strchr(msg_type + 8, ']'); if (end == NULL) return -1; len = end - (msg_type + 8); if (len > 7) len = 7; memset(buf, 0, sizeof(buf)); strncpy(buf, msg_type + 8, len); errno = 0; return strtol(buf, NULL, 10); } else if (isdigit((unsigned char)*msg_type)) { errno = 0; return strtol(msg_type, NULL, 10); } return -1; } const char *audit_msg_type_to_name(int msg_type) { return msg_type_i2s(msg_type); } int audit_name_to_machine(const char *machine) { int res; if (machine_s2i(machine, &res) != 0) return res; return -1; } const char *audit_machine_to_name(int machine) { return machine_i2s(machine); } unsigned int audit_machine_to_elf(int machine) { unsigned int i; for (i = 0; i < AUDIT_ELF_NAMES; i++) if (elftab[i].key == machine) return elftab[i].lvalue; return 0; } int audit_elf_to_machine(unsigned int elf) { unsigned int i; for (i = 0; i < AUDIT_ELF_NAMES; i++) if (elftab[i].lvalue == elf) return elftab[i].key; return -1; } const char *audit_operator_to_symbol(int op) { return op_i2s(op); } /* This function returns 0 on error, otherwise the converted value */ int audit_name_to_errno(const char *error) { #ifndef NO_TABLES int rc, minus = 1; if (*error == '-') { minus = -1; error++; } if (err_s2i(error, &rc) == 0) rc = 0; return rc*minus; #else return 0; #endif } /* This function handles negative numbers */ const char *audit_errno_to_name(int error) { #ifndef NO_TABLES // No error if (error == 0) return NULL; // If negative, turn positive to search on if (error < 0) error *= -1; return err_i2s(error); #else return NULL; #endif } int audit_name_to_ftype(const char *name) { #ifndef NO_TABLES int res; if (ftype_s2i(name, &res) != 0) return res; #endif return -1; } const char *audit_ftype_to_name(int ftype) { #ifndef NO_TABLES return ftype_i2s(ftype); #else return NULL; #endif } int audit_name_to_fstype(const char *name) { #ifndef NO_TABLES int res; if (fstype_s2i(name, &res) != 0) return res; #endif return -1; } const char *audit_fstype_to_name(int fstype) { #ifndef NO_TABLES return fstype_i2s(fstype); #else return NULL; #endif } int audit_name_to_perm(const char *name) { #ifndef NO_TABLES int res; if (perm_s2i(name, &res) != 0) return res; #endif return -1; } const char *audit_perm_to_name(int perm) { #ifndef NO_TABLES return perm_i2s(perm); #else return NULL; #endif } audit-userspace-4.0.5/lib/machinetab.h000066400000000000000000000030771501761310600176370ustar00rootroot00000000000000/* machine.h -- * Copyright 2005-06,2009,2012-13,2022 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" _S(MACH_X86, "i386" ) _S(MACH_X86, "i486" ) _S(MACH_X86, "i586" ) _S(MACH_X86, "i686" ) _S(MACH_86_64, "x86_64" ) _S(MACH_PPC64, "ppc64" ) _S(MACH_PPC64LE, "ppc64le") _S(MACH_PPC, "ppc" ) _S(MACH_S390X, "s390x" ) _S(MACH_S390, "s390" ) #ifdef WITH_ARM _S(MACH_ARM, "armeb" ) _S(MACH_ARM, "arm" ) _S(MACH_ARM, "armv5tejl") _S(MACH_ARM, "armv5tel") _S(MACH_ARM, "armv6l") _S(MACH_ARM, "armv7l") #endif #ifdef WITH_AARCH64 _S(MACH_AARCH64, "aarch64" ) _S(MACH_AARCH64, "armv8l") #endif #ifdef WITH_IO_URING _S(MACH_IO_URING, "uring") #endif #ifdef WITH_RISCV _S(MACH_RISCV32, "riscv32") _S(MACH_RISCV64, "riscv64") #endif audit-userspace-4.0.5/lib/message.c000066400000000000000000000034471501761310600171640ustar00rootroot00000000000000/* message.c -- * Copyright 2004,2005,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include "libaudit.h" #include "private.h" /* The message mode refers to where informational messages go 0 - stderr, 1 - syslog, 2 - quiet. The default is quiet. */ static message_t message_mode = MSG_QUIET; static debug_message_t debug_message = DBG_NO; void set_aumessage_mode(message_t mode, debug_message_t debug) { message_mode = mode; debug_message = debug; } void audit_msg(int priority, const char *fmt, ...) { va_list ap; int saved_errno = errno; if (message_mode == MSG_QUIET) return; if (priority == LOG_DEBUG && debug_message == DBG_NO) return; va_start(ap, fmt); if (message_mode == MSG_SYSLOG) vsyslog(priority, fmt, ap); else { vfprintf(stderr, fmt, ap); fputc('\n', stderr); } va_end( ap ); errno = saved_errno; } audit-userspace-4.0.5/lib/msg_typetab.h000066400000000000000000000401431501761310600200550ustar00rootroot00000000000000/* msg_typetab.h -- * Copyright 2005-07,2009-18,21-23 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ /* * This table is arranged from lowest number to highest number. The * items that are commented out are for completeness. The audit * daemon filters these and they never show up in the logs, therefore * they are not needed for reporting. Or they have been deprecated for * a long time. */ //_S(AUDIT_GET, "GET" ) //_S(AUDIT_SET, "SET" ) //_S(AUDIT_LIST, "LIST" ) //_S(AUDIT_ADD, "ADD" ) //_S(AUDIT_DEL, "DEL" ) _S(AUDIT_USER, "USER" ) _S(AUDIT_LOGIN, "LOGIN" ) //_S(AUDIT_SIGNAL_INFO, "SIGNAL_INFO" ) //_S(AUDIT_ADD_RULE, "ADD_RULE" ) //_S(AUDIT_DEL_RULE, "DEL_RULE" ) //_S(AUDIT_LIST_RULES, "LIST_RULES" ) //_S(AUDIT_TRIM, "TRIM" ) //_S(AUDIT_MAKE_EQUIV, "MAKE_EQUIV" ) //_S(AUDIT_TTY_GET, "TTY_GET" ) //_S(AUDIT_TTY_SET, "TTY_SET" ) //_S(AUDIT_SET_FEATURE, "SET_FEATURE" ) //_S(AUDIT_GET_FEATURE, "GET_FEATURE" ) _S(AUDIT_USER_AUTH, "USER_AUTH" ) _S(AUDIT_USER_ACCT, "USER_ACCT" ) _S(AUDIT_USER_MGMT, "USER_MGMT" ) _S(AUDIT_CRED_ACQ, "CRED_ACQ" ) _S(AUDIT_CRED_DISP, "CRED_DISP" ) _S(AUDIT_USER_START, "USER_START" ) _S(AUDIT_USER_END, "USER_END" ) _S(AUDIT_USER_AVC, "USER_AVC" ) _S(AUDIT_USER_CHAUTHTOK, "USER_CHAUTHTOK" ) _S(AUDIT_USER_ERR, "USER_ERR" ) _S(AUDIT_CRED_REFR, "CRED_REFR" ) _S(AUDIT_USYS_CONFIG, "USYS_CONFIG" ) _S(AUDIT_USER_LOGIN, "USER_LOGIN" ) _S(AUDIT_USER_LOGOUT, "USER_LOGOUT" ) _S(AUDIT_ADD_USER, "ADD_USER" ) _S(AUDIT_DEL_USER, "DEL_USER" ) _S(AUDIT_ADD_GROUP, "ADD_GROUP" ) _S(AUDIT_DEL_GROUP, "DEL_GROUP" ) _S(AUDIT_DAC_CHECK, "DAC_CHECK" ) _S(AUDIT_CHGRP_ID, "CHGRP_ID" ) _S(AUDIT_TEST, "TEST" ) _S(AUDIT_TRUSTED_APP, "TRUSTED_APP" ) _S(AUDIT_USER_SELINUX_ERR, "USER_SELINUX_ERR" ) _S(AUDIT_USER_CMD, "USER_CMD" ) _S(AUDIT_USER_TTY, "USER_TTY" ) _S(AUDIT_CHUSER_ID, "CHUSER_ID" ) _S(AUDIT_GRP_AUTH, "GRP_AUTH" ) _S(AUDIT_MAC_CHECK, "MAC_CHECK" ) _S(AUDIT_ACCT_LOCK, "ACCT_LOCK" ) _S(AUDIT_ACCT_UNLOCK, "ACCT_UNLOCK" ) _S(AUDIT_USER_DEVICE, "USER_DEVICE" ) _S(AUDIT_SOFTWARE_UPDATE, "SOFTWARE_UPDATE" ) _S(AUDIT_SYSTEM_BOOT, "SYSTEM_BOOT" ) _S(AUDIT_SYSTEM_SHUTDOWN, "SYSTEM_SHUTDOWN" ) _S(AUDIT_SYSTEM_RUNLEVEL, "SYSTEM_RUNLEVEL" ) _S(AUDIT_SERVICE_START, "SERVICE_START" ) _S(AUDIT_SERVICE_STOP, "SERVICE_STOP" ) _S(AUDIT_GRP_MGMT, "GRP_MGMT" ) _S(AUDIT_GRP_CHAUTHTOK, "GRP_CHAUTHTOK" ) _S(AUDIT_DAEMON_START, "DAEMON_START" ) _S(AUDIT_DAEMON_END, "DAEMON_END" ) _S(AUDIT_DAEMON_ABORT, "DAEMON_ABORT" ) _S(AUDIT_DAEMON_CONFIG, "DAEMON_CONFIG" ) //_S(AUDIT_DAEMON_RECONFIG, "DAEMON_RECONFIG" ) _S(AUDIT_DAEMON_ROTATE, "DAEMON_ROTATE" ) _S(AUDIT_DAEMON_RESUME, "DAEMON_RESUME" ) _S(AUDIT_DAEMON_ACCEPT, "DAEMON_ACCEPT" ) _S(AUDIT_DAEMON_CLOSE, "DAEMON_CLOSE" ) _S(AUDIT_DAEMON_ERR, "DAEMON_ERR" ) _S(AUDIT_SYSCALL, "SYSCALL" ) //_S(AUDIT_FS_WATCH, "FS_WATCH" ) _S(AUDIT_PATH, "PATH" ) _S(AUDIT_IPC, "IPC" ) _S(AUDIT_SOCKETCALL, "SOCKETCALL" ) _S(AUDIT_CONFIG_CHANGE, "CONFIG_CHANGE" ) _S(AUDIT_SOCKADDR, "SOCKADDR" ) _S(AUDIT_CWD, "CWD" ) //_S(AUDIT_FS_INODE, "FS_INODE" ) _S(AUDIT_EXECVE, "EXECVE" ) _S(AUDIT_IPC_SET_PERM, "IPC_SET_PERM" ) _S(AUDIT_MQ_OPEN, "MQ_OPEN" ) _S(AUDIT_MQ_SENDRECV, "MQ_SENDRECV" ) _S(AUDIT_MQ_NOTIFY, "MQ_NOTIFY" ) _S(AUDIT_MQ_GETSETATTR, "MQ_GETSETATTR" ) _S(AUDIT_KERNEL_OTHER, "KERNEL_OTHER" ) _S(AUDIT_FD_PAIR, "FD_PAIR" ) _S(AUDIT_OBJ_PID, "OBJ_PID" ) _S(AUDIT_TTY, "TTY" ) _S(AUDIT_EOE, "EOE" ) _S(AUDIT_BPRM_FCAPS, "BPRM_FCAPS" ) _S(AUDIT_CAPSET, "CAPSET" ) _S(AUDIT_MMAP, "MMAP" ) _S(AUDIT_NETFILTER_PKT, "NETFILTER_PKT" ) _S(AUDIT_NETFILTER_CFG, "NETFILTER_CFG" ) _S(AUDIT_SECCOMP, "SECCOMP" ) _S(AUDIT_PROCTITLE, "PROCTITLE" ) _S(AUDIT_FEATURE_CHANGE, "FEATURE_CHANGE" ) _S(AUDIT_KERN_MODULE, "KERN_MODULE" ) _S(AUDIT_FANOTIFY, "FANOTIFY" ) _S(AUDIT_TIME_INJOFFSET, "TIME_INJOFFSET" ) _S(AUDIT_TIME_ADJNTPVAL, "TIME_ADJNTPVAL" ) _S(AUDIT_BPF, "BPF" ) _S(AUDIT_EVENT_LISTENER, "EVENT_LISTENER" ) _S(AUDIT_URINGOP, "URINGOP" ) _S(AUDIT_OPENAT2, "OPENAT2" ) _S(AUDIT_DM_CTRL, "DM_CTRL" ) _S(AUDIT_DM_EVENT, "DM_EVENT" ) _S(AUDIT_AVC, "AVC" ) _S(AUDIT_SELINUX_ERR, "SELINUX_ERR" ) _S(AUDIT_AVC_PATH, "AVC_PATH" ) _S(AUDIT_MAC_POLICY_LOAD, "MAC_POLICY_LOAD" ) _S(AUDIT_MAC_STATUS, "MAC_STATUS" ) _S(AUDIT_MAC_CONFIG_CHANGE, "MAC_CONFIG_CHANGE" ) _S(AUDIT_MAC_UNLBL_ALLOW, "MAC_UNLBL_ALLOW" ) _S(AUDIT_MAC_CIPSOV4_ADD, "MAC_CIPSOV4_ADD" ) _S(AUDIT_MAC_CIPSOV4_DEL, "MAC_CIPSOV4_DEL" ) _S(AUDIT_MAC_MAP_ADD, "MAC_MAP_ADD" ) _S(AUDIT_MAC_MAP_DEL, "MAC_MAP_DEL" ) _S(AUDIT_MAC_IPSEC_ADDSA, "MAC_IPSEC_ADDSA" ) _S(AUDIT_MAC_IPSEC_DELSA, "MAC_IPSEC_DELSA" ) _S(AUDIT_MAC_IPSEC_ADDSPD, "MAC_IPSEC_ADDSPD" ) _S(AUDIT_MAC_IPSEC_DELSPD, "MAC_IPSEC_DELSPD" ) _S(AUDIT_MAC_IPSEC_EVENT, "MAC_IPSEC_EVENT" ) _S(AUDIT_MAC_UNLBL_STCADD, "MAC_UNLBL_STCADD" ) _S(AUDIT_MAC_UNLBL_STCDEL, "MAC_UNLBL_STCDEL" ) _S(AUDIT_MAC_CALIPSO_ADD, "MAC_CALIPSO_ADD" ) _S(AUDIT_MAC_CALIPSO_DEL, "MAC_CALIPSO_DEL" ) _S(AUDIT_ANOM_PROMISCUOUS, "ANOM_PROMISCUOUS" ) _S(AUDIT_ANOM_ABEND, "ANOM_ABEND" ) _S(AUDIT_ANOM_LINK, "ANOM_LINK" ) _S(AUDIT_ANOM_CREAT, "ANOM_CREAT" ) _S(AUDIT_INTEGRITY_DATA, "INTEGRITY_DATA" ) _S(AUDIT_INTEGRITY_METADATA, "INTEGRITY_METADATA" ) _S(AUDIT_INTEGRITY_STATUS, "INTEGRITY_STATUS" ) _S(AUDIT_INTEGRITY_HASH, "INTEGRITY_HASH" ) _S(AUDIT_INTEGRITY_PCR, "INTEGRITY_PCR" ) _S(AUDIT_INTEGRITY_RULE, "INTEGRITY_RULE" ) _S(AUDIT_INTEGRITY_EVM_XATTR, "INTEGRITY_EVM_XATTR" ) _S(AUDIT_INTEGRITY_POLICY_RULE, "INTEGRITY_POLICY_RULE" ) #ifdef WITH_APPARMOR _S(AUDIT_AA, "APPARMOR" ) _S(AUDIT_APPARMOR_AUDIT, "APPARMOR_AUDIT" ) _S(AUDIT_APPARMOR_ALLOWED, "APPARMOR_ALLOWED" ) _S(AUDIT_APPARMOR_DENIED, "APPARMOR_DENIED" ) _S(AUDIT_APPARMOR_HINT, "APPARMOR_HINT" ) _S(AUDIT_APPARMOR_STATUS, "APPARMOR_STATUS" ) _S(AUDIT_APPARMOR_ERROR, "APPARMOR_ERROR" ) _S(AUDIT_APPARMOR_KILL, "APPARMOR_KILL" ) #endif _S(AUDIT_KERNEL, "KERNEL" ) _S(AUDIT_ANOM_LOGIN_FAILURES, "ANOM_LOGIN_FAILURES" ) _S(AUDIT_ANOM_LOGIN_TIME, "ANOM_LOGIN_TIME" ) _S(AUDIT_ANOM_LOGIN_SESSIONS, "ANOM_LOGIN_SESSIONS" ) _S(AUDIT_ANOM_LOGIN_ACCT, "ANOM_LOGIN_ACCT" ) _S(AUDIT_ANOM_LOGIN_LOCATION, "ANOM_LOGIN_LOCATION" ) _S(AUDIT_ANOM_MAX_DAC, "ANOM_MAX_DAC" ) _S(AUDIT_ANOM_MAX_MAC, "ANOM_MAX_MAC" ) _S(AUDIT_ANOM_AMTU_FAIL, "ANOM_AMTU_FAIL" ) _S(AUDIT_ANOM_RBAC_FAIL, "ANOM_RBAC_FAIL" ) _S(AUDIT_ANOM_RBAC_INTEGRITY_FAIL, "ANOM_RBAC_INTEGRITY_FAIL" ) _S(AUDIT_ANOM_CRYPTO_FAIL, "ANOM_CRYPTO_FAIL" ) _S(AUDIT_ANOM_ACCESS_FS, "ANOM_ACCESS_FS" ) _S(AUDIT_ANOM_EXEC, "ANOM_EXEC" ) _S(AUDIT_ANOM_MK_EXEC, "ANOM_MK_EXEC" ) _S(AUDIT_ANOM_ADD_ACCT, "ANOM_ADD_ACCT" ) _S(AUDIT_ANOM_DEL_ACCT, "ANOM_DEL_ACCT" ) _S(AUDIT_ANOM_MOD_ACCT, "ANOM_MOD_ACCT" ) _S(AUDIT_ANOM_ROOT_TRANS, "ANOM_ROOT_TRANS" ) _S(AUDIT_ANOM_LOGIN_SERVICE, "ANOM_LOGIN_SERVICE" ) _S(AUDIT_ANOM_LOGIN_ROOT, "ANOM_LOGIN_ROOT" ) _S(AUDIT_ANOM_ORIGIN_FAILURES, "ANOM_ORIGIN_FAILURES" ) _S(AUDIT_ANOM_SESSION, "ANOM_SESSION" ) _S(AUDIT_RESP_ANOMALY, "RESP_ANOMALY" ) _S(AUDIT_RESP_ALERT, "RESP_ALERT" ) _S(AUDIT_RESP_KILL_PROC, "RESP_KILL_PROC" ) _S(AUDIT_RESP_TERM_ACCESS, "RESP_TERM_ACCESS" ) _S(AUDIT_RESP_ACCT_REMOTE, "RESP_ACCT_REMOTE" ) _S(AUDIT_RESP_ACCT_LOCK_TIMED, "RESP_ACCT_LOCK_TIMED" ) _S(AUDIT_RESP_ACCT_UNLOCK_TIMED, "RESP_ACCT_UNLOCK_TIMED" ) _S(AUDIT_RESP_ACCT_LOCK, "RESP_ACCT_LOCK" ) _S(AUDIT_RESP_TERM_LOCK, "RESP_TERM_LOCK" ) _S(AUDIT_RESP_SEBOOL, "RESP_SEBOOL" ) _S(AUDIT_RESP_EXEC, "RESP_EXEC" ) _S(AUDIT_RESP_SINGLE, "RESP_SINGLE" ) _S(AUDIT_RESP_HALT, "RESP_HALT" ) _S(AUDIT_RESP_ORIGIN_BLOCK, "RESP_ORIGIN_BLOCK" ) _S(AUDIT_RESP_ORIGIN_BLOCK_TIMED, "RESP_ORIGIN_BLOCK_TIMED" ) _S(AUDIT_RESP_ORIGIN_UNBLOCK_TIMED, "RESP_ORIGIN_UNBLOCK_TIMED" ) _S(AUDIT_USER_ROLE_CHANGE, "USER_ROLE_CHANGE" ) _S(AUDIT_ROLE_ASSIGN, "ROLE_ASSIGN" ) _S(AUDIT_ROLE_REMOVE, "ROLE_REMOVE" ) _S(AUDIT_LABEL_OVERRIDE, "LABEL_OVERRIDE" ) _S(AUDIT_LABEL_LEVEL_CHANGE, "LABEL_LEVEL_CHANGE" ) _S(AUDIT_USER_LABELED_EXPORT, "USER_LABELED_EXPORT" ) _S(AUDIT_USER_UNLABELED_EXPORT, "USER_UNLABELED_EXPORT" ) _S(AUDIT_DEV_ALLOC, "DEV_ALLOC" ) _S(AUDIT_DEV_DEALLOC, "DEV_DEALLOC" ) _S(AUDIT_FS_RELABEL, "FS_RELABEL" ) _S(AUDIT_USER_MAC_POLICY_LOAD, "USER_MAC_POLICY_LOAD" ) _S(AUDIT_ROLE_MODIFY, "ROLE_MODIFY" ) _S(AUDIT_USER_MAC_CONFIG_CHANGE, "USER_MAC_CONFIG_CHANGE" ) _S(AUDIT_USER_MAC_STATUS, "USER_MAC_STATUS" ) _S(AUDIT_CRYPTO_TEST_USER, "CRYPTO_TEST_USER" ) _S(AUDIT_CRYPTO_PARAM_CHANGE_USER, "CRYPTO_PARAM_CHANGE_USER" ) _S(AUDIT_CRYPTO_LOGIN, "CRYPTO_LOGIN" ) _S(AUDIT_CRYPTO_LOGOUT, "CRYPTO_LOGOUT" ) _S(AUDIT_CRYPTO_KEY_USER, "CRYPTO_KEY_USER" ) _S(AUDIT_CRYPTO_FAILURE_USER, "CRYPTO_FAILURE_USER" ) _S(AUDIT_CRYPTO_REPLAY_USER, "CRYPTO_REPLAY_USER" ) _S(AUDIT_CRYPTO_SESSION, "CRYPTO_SESSION" ) _S(AUDIT_CRYPTO_IKE_SA, "CRYPTO_IKE_SA" ) _S(AUDIT_CRYPTO_IPSEC_SA, "CRYPTO_IPSEC_SA" ) _S(AUDIT_VIRT_CONTROL, "VIRT_CONTROL" ) _S(AUDIT_VIRT_RESOURCE, "VIRT_RESOURCE" ) _S(AUDIT_VIRT_MACHINE_ID, "VIRT_MACHINE_ID" ) _S(AUDIT_VIRT_INTEGRITY_CHECK, "VIRT_INTEGRITY_CHECK" ) _S(AUDIT_VIRT_CREATE, "VIRT_CREATE" ) _S(AUDIT_VIRT_DESTROY, "VIRT_DESTROY" ) _S(AUDIT_VIRT_MIGRATE_IN, "VIRT_MIGRATE_IN" ) _S(AUDIT_VIRT_MIGRATE_OUT, "VIRT_MIGRATE_OUT" ) audit-userspace-4.0.5/lib/netlink.c000066400000000000000000000162041501761310600171770ustar00rootroot00000000000000/* netlink.c -- * Copyright 2004,2005,2009,2013,2016 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith */ #include "config.h" #include #include #include #include #include #include #include #include "libaudit.h" #include "private.h" #ifndef NETLINK_AUDIT #define NETLINK_AUDIT 9 #endif static int adjust_reply(struct audit_reply *rep, int len); static int check_ack(int fd); /* * This function opens a connection to the kernel's audit * subsystem. You must be root for the call to succeed. On error, * a negative value is returned. On success, the file descriptor is * returned - which can be 0 or higher. */ int audit_open(void) { int fd = socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT); if (fd < 0) { if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) audit_msg(LOG_ERR, "Error - audit support not in kernel"); else audit_msg(LOG_ERR, "Error opening audit netlink socket (%s)", strerror(errno)); } return fd; } void audit_close(int fd) { if (fd >= 0) close(fd); } /* * This function returns -errno on error, 0 if error response received, * and > 0 if packet OK. */ int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek) { int len; struct sockaddr_nl nladdr; socklen_t nladdrlen = sizeof(nladdr); if (fd < 0) return -EBADF; if (block == GET_REPLY_NONBLOCKING) peek |= MSG_DONTWAIT; retry: len = recvfrom(fd, &rep->msg, sizeof(rep->msg), peek, (struct sockaddr*)&nladdr, &nladdrlen); if (len < 0) { if (errno == EINTR) goto retry; if (errno != EAGAIN) audit_msg(LOG_ERR, "Error receiving audit netlink packet (%s)", strerror(errno)); return -errno; } if (nladdrlen != sizeof(nladdr)) { audit_msg(LOG_ERR, "Bad address size reading audit netlink socket"); return -EPROTO; } if (nladdr.nl_pid) { audit_msg(LOG_ERR, "Spoofed packet received on audit netlink socket"); return -EINVAL; } len = adjust_reply(rep, len); if (len == 0) len = -errno; return len; } /* * This function returns 0 on error and len on success. */ static int adjust_reply(struct audit_reply *rep, int len) { rep->type = rep->msg.nlh.nlmsg_type; rep->len = rep->msg.nlh.nlmsg_len; rep->nlh = &rep->msg.nlh; rep->status = NULL; rep->ruledata = NULL; rep->login = NULL; rep->message = NULL; rep->error = NULL; rep->signal_info = NULL; rep->conf = NULL; #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 rep->features = NULL; #endif if (!NLMSG_OK(rep->nlh, (unsigned int)len)) { if (len == sizeof(rep->msg)) { audit_msg(LOG_ERR, "Netlink event from kernel is too big"); errno = EFBIG; } else { audit_msg(LOG_ERR, "Netlink message from kernel was not OK"); errno = EBADE; } return 0; } /* Next we'll set the data structure to point to msg.data. This is * to avoid having to use casts later. */ switch (rep->type) { case NLMSG_ERROR: rep->error = NLMSG_DATA(rep->nlh); break; case AUDIT_GET: rep->status = NLMSG_DATA(rep->nlh); break; #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 case AUDIT_GET_FEATURE: rep->features = NLMSG_DATA(rep->nlh); break; #endif case AUDIT_LIST_RULES: rep->ruledata = NLMSG_DATA(rep->nlh); break; case AUDIT_USER: case AUDIT_LOGIN: case AUDIT_KERNEL: case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG: case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2: case AUDIT_FIRST_EVENT...AUDIT_INTEGRITY_LAST_MSG: rep->message = NLMSG_DATA(rep->nlh); break; case AUDIT_SIGNAL_INFO: rep->signal_info = NLMSG_DATA(rep->nlh); break; } return len; } /* * Return values: success: positive non-zero sequence number * error: -errno * short: 0 */ int __audit_send(int fd, int type, const void *data, unsigned int size, int *seq) { static int sequence = 0; struct audit_message req; int retval; struct sockaddr_nl addr; /* Due to user space library callbacks, there's a chance that a -1 for the fd could be passed. Just check for and handle it. */ if (fd < 0) { errno = EBADF; return -errno; } if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) { errno = EINVAL; return -errno; } if (sequence == INT_MAX) sequence = 1; else sequence++; *seq = sequence; memset(&req, 0, sizeof(req)); req.nlh.nlmsg_len = NLMSG_SPACE(size); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; req.nlh.nlmsg_seq = sequence; if (size && data) memcpy(NLMSG_DATA(&req.nlh), data, size); memset(&addr, 0, sizeof(addr)); addr.nl_family = AF_NETLINK; addr.nl_pid = 0; addr.nl_groups = 0; do { retval = sendto(fd, &req, req.nlh.nlmsg_len, 0, (struct sockaddr*)&addr, sizeof(addr)); } while (retval < 0 && errno == EINTR); if (retval == (int)req.nlh.nlmsg_len) return check_ack(fd); if (retval < 0) { return -errno; } else if (retval > 0) { errno = EINVAL; return -errno; } return 0; } int audit_send(int fd, int type, const void *data, unsigned int size) { int rc; int seq; rc = __audit_send(fd, type, data, size, &seq); if (rc == 0) rc = seq; return rc; } /* * This function will take a peek into the next packet and see if there's * an error. If so, the error is returned and its non-zero. Otherwise a * zero is returned indicating that we don't know of any problems. */ static int check_ack(int fd) { int rc, retries = 80; struct audit_reply rep; struct pollfd pfd[1]; retry: pfd[0].fd = fd; pfd[0].events = POLLIN; do { rc = poll(pfd, 1, 500); /* .5 second */ } while (rc < 0 && errno == EINTR); /* We don't look at rc from above as it doesn't matter. We are * going to try to read nonblocking just in case packet shows up. */ /* NOTE: whatever is returned is treated as the errno */ rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, MSG_PEEK); if (rc == -EAGAIN && retries) { retries--; goto retry; } else if (rc < 0) return rc; else if (rc == 0) return -EINVAL; /* This can't happen anymore */ else if (rc > 0 && rep.type == NLMSG_ERROR) { int error = rep.error->error; /* Eat the message */ if (audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0)) ; // intentionally empty /* NLMSG_ERROR can indicate success, only report nonzero */ if (error) { errno = -error; return error; } } return 0; } audit-userspace-4.0.5/lib/optab.h000066400000000000000000000023711501761310600166450ustar00rootroot00000000000000/* optab.h -- * Copyright 2005-07 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(AUDIT_EQUAL, "=" ) _S(AUDIT_NOT_EQUAL, "!=" ) _S(AUDIT_GREATER_THAN, ">" ) _S(AUDIT_GREATER_THAN_OR_EQUAL, ">=" ) _S(AUDIT_LESS_THAN, "<" ) _S(AUDIT_LESS_THAN_OR_EQUAL, "<=" ) _S(AUDIT_BIT_MASK, "&" ) _S(AUDIT_BIT_TEST, "&=" ) audit-userspace-4.0.5/lib/permtab.h000066400000000000000000000030541501761310600171710ustar00rootroot00000000000000/* permtab.h -- * Copyright 2023 Red Hat Inc. * All Rights Reserved. * * 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; see the file COPYING.lib. If not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * * Source of info: include/asm-generic/audit_*.h * arch/x86/kernel/audit_64.c * */ _S(AUDIT_PERM_EXEC, "execve") _S(AUDIT_PERM_WRITE, "rename,mkdir,rmdir,creat,link,unlink,symlink,mknod,mkdirat,mknodat,unlinkat,renameat,linkat,symlinkat,renameat2,acct,swapon,quotactl,truncate,ftruncate,bind,fallocate,open,openat,openat2") _S(AUDIT_PERM_READ, "readlink,quotactl,listxattr,listxattrat,llistxattr,flistxattr,getxattr,getxattrat,lgetxattr,fgetxattr,readlinkat,open,openat,openat2") _S(AUDIT_PERM_ATTR, "chmod,fchmod,chown,lchown,fchown,setxattr,setxattrat,lsetxattr,fsetxattr,removexattr,removexattrat,lremovexattr,fremovexattr,fchownat,fchmodat,link,linkat") audit-userspace-4.0.5/lib/ppc_table.h000066400000000000000000000242571501761310600175000ustar00rootroot00000000000000/* ppc_table.h -- * Copyright 2005-09,2011-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(0, "restart_syscall") _S(1, "exit") _S(2, "fork") _S(3, "read") _S(4, "write") _S(5, "open") _S(6, "close") _S(7, "waitpid") _S(8, "creat") _S(9, "link") _S(10, "unlink") _S(11, "execve") _S(12, "chdir") _S(13, "time") _S(14, "mknod") _S(15, "chmod") _S(16, "lchown") _S(17, "break") _S(18, "oldstat") _S(19, "lseek") _S(20, "getpid") _S(21, "mount") _S(22, "umount") _S(23, "setuid") _S(24, "getuid") _S(25, "stime") _S(26, "ptrace") _S(27, "alarm") _S(28, "oldfstat") _S(29, "pause") _S(30, "utime") _S(31, "stty") _S(32, "gtty") _S(33, "access") _S(34, "nice") _S(35, "ftime") _S(36, "sync") _S(37, "kill") _S(38, "rename") _S(39, "mkdir") _S(40, "rmdir") _S(41, "dup") _S(42, "pipe") _S(43, "times") _S(44, "prof") _S(45, "brk") _S(46, "setgid") _S(47, "getgid") _S(48, "signal") _S(49, "geteuid") _S(50, "getegid") _S(51, "acct") _S(52, "umount2") _S(53, "lock") _S(54, "ioctl") _S(55, "fcntl") _S(56, "mpx") _S(57, "setpgid") _S(58, "ulimit") _S(59, "oldolduname") _S(60, "umask") _S(61, "chroot") _S(62, "ustat") _S(63, "dup2") _S(64, "getppid") _S(65, "getpgrp") _S(66, "setsid") _S(67, "sigaction") _S(68, "sgetmask") _S(69, "ssetmask") _S(70, "setreuid") _S(71, "setregid") _S(72, "sigsuspend") _S(73, "sigpending") _S(74, "sethostname") _S(75, "setrlimit") _S(76, "getrlimit") _S(77, "getrusage") _S(78, "gettimeofday") _S(79, "settimeofday") _S(80, "getgroups") _S(81, "setgroups") _S(82, "select") _S(83, "symlink") _S(84, "oldlstat") _S(85, "readlink") _S(86, "uselib") _S(87, "swapon") _S(88, "reboot") _S(89, "readdir") _S(90, "mmap") _S(91, "munmap") _S(92, "truncate") _S(93, "ftruncate") _S(94, "fchmod") _S(95, "fchown") _S(96, "getpriority") _S(97, "setpriority") _S(98, "profil") _S(99, "statfs") _S(100, "fstatfs") _S(101, "ioperm") _S(102, "socketcall") _S(103, "syslog") _S(104, "setitimer") _S(105, "getitimer") _S(106, "stat") _S(107, "lstat") _S(108, "fstat") _S(109, "olduname") _S(110, "iopl") _S(111, "vhangup") _S(112, "idle") _S(113, "vm86") _S(114, "wait4") _S(115, "swapoff") _S(116, "sysinfo") _S(117, "ipc") _S(118, "fsync") _S(119, "sigreturn") _S(120, "clone") _S(121, "setdomainname") _S(122, "uname") _S(123, "modify_ldt") _S(124, "adjtimex") _S(125, "mprotect") _S(126, "sigprocmask") _S(127, "create_module") _S(128, "init_module") _S(129, "delete_module") _S(130, "get_kernel_syms") _S(131, "quotactl") _S(132, "getpgid") _S(133, "fchdir") _S(134, "bdflush") _S(135, "sysfs") _S(136, "personality") _S(137, "afs_syscall") _S(138, "setfsuid") _S(139, "setfsgid") _S(140, "_llseek") _S(141, "getdents") _S(142, "_newselect") _S(143, "flock") _S(144, "msync") _S(145, "readv") _S(146, "writev") _S(147, "getsid") _S(148, "fdatasync") _S(149, "_sysctl") _S(150, "mlock") _S(151, "munlock") _S(152, "mlockall") _S(153, "munlockall") _S(154, "sched_setparam") _S(155, "sched_getparam") _S(156, "sched_setscheduler") _S(157, "sched_getscheduler") _S(158, "sched_yield") _S(159, "sched_get_priority_max") _S(160, "sched_get_priority_min") _S(161, "sched_rr_get_interval") _S(162, "nanosleep") _S(163, "mremap") _S(164, "setresuid") _S(165, "getresuid") _S(166, "query_module") _S(167, "poll") _S(168, "nfsservctl") _S(169, "setresgid") _S(170, "getresgid") _S(171, "prctl") _S(172, "rt_sigreturn") _S(173, "rt_sigaction") _S(174, "rt_sigprocmask") _S(175, "rt_sigpending") _S(176, "rt_sigtimedwait") _S(177, "rt_sigqueueinfo") _S(178, "rt_sigsuspend") _S(179, "pread") _S(180, "pwrite") _S(181, "chown") _S(182, "getcwd") _S(183, "capget") _S(184, "capset") _S(185, "sigaltstack") _S(186, "sendfile") _S(187, "getpmsg") _S(188, "putpmsg") _S(189, "vfork") _S(190, "ugetrlimit") _S(191, "readahead") _S(192, "mmap2") _S(193, "truncate64") _S(194, "ftruncate64") _S(195, "stat64") _S(196, "lstat64") _S(197, "fstat64") _S(198, "pciconfig_read") _S(199, "pciconfig_write") _S(200, "pciconfig_iobase") _S(201, "multiplexer") _S(202, "getdents64") _S(203, "pivot_root") _S(204, "fcntl64") _S(205, "madvise") _S(206, "mincore") _S(207, "gettid") _S(208, "tkill") _S(209, "setxattr") _S(210, "lsetxattr") _S(211, "fsetxattr") _S(212, "getxattr") _S(213, "lgetxattr") _S(214, "fgetxattr") _S(215, "listxattr") _S(216, "llistxattr") _S(217, "flistxattr") _S(218, "removexattr") _S(219, "lremovexattr") _S(220, "fremovexattr") _S(221, "futex") _S(222, "sched_setaffinity") _S(223, "sched_getaffinity") _S(225, "tuxcall") _S(226, "sendfile64") _S(227, "io_setup") _S(228, "io_destroy") _S(229, "io_getevents") _S(230, "io_submit") _S(231, "io_cancel") _S(232, "set_tid_address") _S(233, "fadvise64") _S(234, "exit_group") _S(235, "lookup_dcookie") _S(236, "epoll_create") _S(237, "epoll_ctl") _S(238, "epoll_wait") _S(239, "remap_file_pages") _S(240, "timer_create") _S(241, "timer_settime") _S(242, "timer_gettime") _S(243, "timer_getoverrun") _S(244, "timer_delete") _S(245, "clock_settime") _S(246, "clock_gettime") _S(247, "clock_getres") _S(248, "clock_nanosleep") _S(249, "swapcontext") _S(250, "tgkill") _S(251, "utimes") _S(252, "statfs64") _S(253, "fstatfs64") _S(254, "fadvise64_64") _S(255, "rtas") _S(256, "sys_debug_setcontext") // 257 reserved for vserver _S(258, "migrate_pages") _S(259, "mbind") _S(260, "get_mempolicy") _S(261, "set_mempolicy") _S(262, "mq_open") _S(263, "mq_unlink") _S(264, "mq_timedsend") _S(265, "mq_timedreceive") _S(266, "mq_notify") _S(267, "mq_getsetattr") _S(268, "kexec_load") _S(269, "add_key") _S(270, "request_key") _S(271, "keyctl") _S(272, "waitid") _S(273, "ioprio_set") _S(274, "ioprio_get") _S(275, "inotify_init") _S(276, "inotify_add_watch") _S(277, "inotify_rm_watch") _S(278, "spu_run") _S(279, "spu_create") _S(280, "pselect6") _S(281, "ppoll") _S(282, "unshare") _S(283, "splice") _S(284, "tee") _S(285, "vmsplice") _S(286, "openat") _S(287, "mkdirat") _S(288, "mknodat") _S(289, "fchownat") _S(290, "futimesat") _S(291, "fstatat64") _S(292, "unlinkat") _S(293, "renameat") _S(294, "linkat") _S(295, "symlinkat") _S(296, "readlinkat") _S(297, "fchmodat") _S(298, "faccessat") _S(299, "get_robust_list") _S(300, "set_robust_list") _S(301, "move_pages") _S(302, "getcpu") _S(303, "epoll_pwait") _S(304, "utimensat") _S(305, "signalfd") _S(306, "timerfd") _S(307, "eventfd") _S(308, "sync_file_range2") _S(309, "fallocate") _S(310, "subpage_prot") _S(311, "timerfd_settime") _S(312, "timerfd_gettime") _S(313, "signalfd4") _S(314, "eventfd2") _S(315, "epoll_create1") _S(316, "dup3") _S(317, "pipe2") _S(318, "inotify_init1") _S(319, "perf_counter_open") _S(320, "preadv") _S(321, "pwritev") _S(322, "rt_tgsigqueueinfo") _S(323, "fanotify_init") _S(324, "fanotify_mark") _S(325, "prlimit64") _S(326, "socket") _S(327, "bind") _S(328, "connect") _S(329, "listen") _S(330, "accept") _S(331, "getsockname") _S(332, "getpeername") _S(333, "socketpair") _S(334, "send") _S(335, "sendto") _S(336, "recv") _S(337, "recvfrom") _S(338, "shutdown") _S(339, "setsockopt") _S(340, "getsockopt") _S(341, "sendmsg") _S(342, "recvmsg") _S(343, "recvmmsg") _S(344, "accept4") _S(345, "name_to_handle_at") _S(346, "open_by_handle_at") _S(347, "clock_adjtime") _S(348, "syncfs") _S(349, "sendmmsg") _S(350, "setns") _S(351, "process_vm_readv") _S(352, "process_vm_writev") _S(353, "finit_module") _S(354, "kcmp") _S(355, "sched_setattr") _S(356, "sched_getattr") _S(357, "renameat2") _S(358, "seccomp") _S(359, "getrandom") _S(360, "memfd_create") _S(361, "bpf") _S(362, "execveat") _S(363, "switch_endian") _S(364, "userfaultfd") _S(365, "membarrier") // 366 - 377 originally left for IPC, now unused _S(378, "mlock2") _S(379, "copy_file_range") _S(380, "preadv2") _S(381, "pwritev2") _S(382, "kexec_file_load") _S(383, "statx") _S(384, "pkey_alloc") _S(385, "pkey_free") _S(386, "pkey_mprotect") _S(387, "rseq") _S(388, "io_pgetevents") _S(392, "semtimedop") _S(393, "semget") _S(394, "semctl") _S(395, "shmget") _S(396, "shmctl") _S(397, "shmat") _S(398, "shmdt") _S(399, "msgget") _S(400, "msgsnd") _S(401, "msgrcv") _S(402, "msgctl") _S(403, "clock_gettime64") _S(404, "clock_settime64") _S(405, "clock_adjtime64") _S(406, "clock_getres_time64") _S(407, "clock_nanosleep_time64") _S(408, "timer_gettime64") _S(409, "timer_settime64") _S(410, "timerfd_gettime64") _S(411, "timerfd_settime64") _S(412, "utimensat_time64") _S(413, "pselect6_time64") _S(414, "ppoll_time64") _S(416, "io_pgetevents_time64") _S(417, "recvmmsg_time64") _S(418, "mq_timedsend_time64") _S(419, "mq_timedreceive_time64") _S(420, "semtimedop_time64") _S(421, "rt_sigtimedwait_time64") _S(422, "futex_time64") _S(423, "sched_rr_get_interval_time64") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/private.h000066400000000000000000000115761501761310600172210ustar00rootroot00000000000000/* private.h -- * Copyright 2005,2006,2009,2013-14 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef _PRIVATE_H_ #define _PRIVATE_H_ #include "dso.h" #ifdef __cplusplus extern "C" { #endif typedef enum { REAL_ERR, HIDE_IT } hide_t; /* This structure is for protocol reference only. All fields are packed and in network order (LSB first). */ struct auditd_remote_message_wrapper { /* The magic number shall never have LF (0x0a) as one of its bytes. */ uint32_t magic; /* Bumped when the layout of this structure changes. */ uint8_t header_version; /* The minimum support needed to understand this message type. * Normally zero. */ uint8_t message_version; /* Upper 8 bits are generic type, see below. */ uint32_t type; /* Number of bytes that follow this header Must be 0..MAX_AUDIT_MESSAGE_LENGTH. */ uint16_t length; /* Copied from message to its reply. */ uint32_t sequence_id; /* The message follows for LENGTH bytes. */ }; #define AUDIT_RMW_HEADER_SIZE 16 /* The magic number shall never have LF (0x0a) as one of its bytes. */ #define AUDIT_RMW_MAGIC 0xff0000feUL #define AUDIT_RMW_HEADER_VERSION 0 /* If set, this is a reply. */ #define AUDIT_RMW_TYPE_REPLYMASK 0x40000000 /* If set, this reply indicates a fatal error of some sort. */ #define AUDIT_RMW_TYPE_FATALMASK 0x20000000 /* If set, this reply indicates success but with some warnings. */ #define AUDIT_RMW_TYPE_WARNMASK 0x10000000 /* This part of the message type is the details for the above. */ #define AUDIT_RMW_TYPE_DETAILMASK 0x000FFFFF /* Version 0 messages. */ #define AUDIT_RMW_TYPE_MESSAGE 0x00000000 #define AUDIT_RMW_TYPE_HEARTBEAT 0x00000001 #define AUDIT_RMW_TYPE_ACK 0x40000000 #define AUDIT_RMW_TYPE_ENDING 0x40000001 #define AUDIT_RMW_TYPE_DISKLOW 0x50000001 #define AUDIT_RMW_TYPE_DISKFULL 0x60000001 #define AUDIT_RMW_TYPE_DISKERROR 0x60000002 /* These next four should not be called directly. */ #define _AUDIT_RMW_PUTN32(header,i,v) \ header[i] = v & 0xff; \ header[i+1] = (v>>8) & 0xff; \ header[i+2] = (v>>16) & 0xff; \ header[i+3] = (v>>24) & 0xff; #define _AUDIT_RMW_PUTN16(header,i,v) \ header[i] = v & 0xff; \ header[i+1] = (v>>8) & 0xff; #define _AUDIT_RMW_GETN32(header,i) \ (((uint32_t)(header[i] & 0xFF)) | \ (((uint32_t)(header[i+1] & 0xFF))<<8) | \ (((uint32_t)(header[i+2] & 0xFF ))<<16) | \ (((uint32_t)(header[i+3] & 0xFF))<<24)) #define _AUDIT_RMW_GETN16(header,i) \ ((uint32_t)(header[i] & 0xFF) | ((uint32_t)(header[i+1] & 0xFF)<<8)) /* For these, HEADER must by of type "unsigned char *" or "unsigned char []" */ #define AUDIT_RMW_PACK_HEADER(header,mver,type,len,seq) \ _AUDIT_RMW_PUTN32 (header,0, AUDIT_RMW_MAGIC); \ header[4] = AUDIT_RMW_HEADER_VERSION; \ header[5] = mver; \ _AUDIT_RMW_PUTN32 (header,6, type); \ _AUDIT_RMW_PUTN16 (header,10, len); \ _AUDIT_RMW_PUTN32 (header,12, seq); #define AUDIT_RMW_IS_MAGIC(header,length) \ (length >= 4 && _AUDIT_RMW_GETN32 (header,0) == AUDIT_RMW_MAGIC) #define AUDIT_RMW_UNPACK_HEADER(header,hver,mver,type,len,seq) \ hver = header[4]; \ mver = header[5]; \ type = _AUDIT_RMW_GETN32 (header,6); \ len = _AUDIT_RMW_GETN16 (header,10); \ seq = _AUDIT_RMW_GETN32 (header,12); /* General */ /* Internal syslog messaging */ void audit_msg(int priority, const char *fmt, ...) #ifdef __GNUC__ __attribute__ ((format (printf, 2, 3))); #else ; #endif extern int audit_send(int fd, int type, const void *data, unsigned int size); extern int __audit_send(int fd, int type, const void *data, unsigned int size, int *seq); AUDIT_HIDDEN_START // This is the main messaging function used internally extern int audit_send_user_message(int fd, int type, hide_t hide_err, const char *message); int audit_name_to_perm(const char *name); const char *audit_perm_to_name(int perm); AUDIT_HIDDEN_END // libaudit.c int _audit_parse_syscall(const char *optarg, struct audit_rule_data *rule); extern int _audit_permadded; extern int _audit_archadded; extern int _audit_syscalladded; extern int _audit_exeadded; extern int _audit_filterfsadded; extern unsigned int _audit_elf; #ifdef __cplusplus } #endif #endif audit-userspace-4.0.5/lib/riscv32_table.h000066400000000000000000000167621501761310600202130ustar00rootroot00000000000000/* riscv32_table.h -- * Copyright 2024 Rivos Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * David Abdurachmanov */ _S(0, "io_setup") _S(1, "io_destroy") _S(2, "io_submit") _S(3, "io_cancel") _S(5, "setxattr") _S(6, "lsetxattr") _S(7, "fsetxattr") _S(8, "getxattr") _S(9, "lgetxattr") _S(10, "fgetxattr") _S(11, "listxattr") _S(12, "llistxattr") _S(13, "flistxattr") _S(14, "removexattr") _S(15, "lremovexattr") _S(16, "fremovexattr") _S(17, "getcwd") _S(18, "lookup_dcookie") _S(19, "eventfd2") _S(20, "epoll_create1") _S(21, "epoll_ctl") _S(22, "epoll_pwait") _S(23, "dup") _S(24, "dup3") _S(25, "fcntl64") _S(26, "inotify_init1") _S(27, "inotify_add_watch") _S(28, "inotify_rm_watch") _S(29, "ioctl") _S(30, "ioprio_set") _S(31, "ioprio_get") _S(32, "flock") _S(33, "mknodat") _S(34, "mkdirat") _S(35, "unlinkat") _S(36, "symlinkat") _S(37, "linkat") _S(39, "umount2") _S(40, "mount") _S(41, "pivot_root") _S(42, "nfsservctl") _S(43, "statfs64") _S(44, "fstatfs64") _S(45, "truncate64") _S(46, "ftruncate64") _S(47, "fallocate") _S(48, "faccessat") _S(49, "chdir") _S(50, "fchdir") _S(51, "chroot") _S(52, "fchmod") _S(53, "fchmodat") _S(54, "fchownat") _S(55, "fchown") _S(56, "openat") _S(57, "close") _S(58, "vhangup") _S(59, "pipe2") _S(60, "quotactl") _S(61, "getdents64") _S(62, "llseek") _S(63, "read") _S(64, "write") _S(65, "readv") _S(66, "writev") _S(67, "pread64") _S(68, "pwrite64") _S(69, "preadv") _S(70, "pwritev") _S(71, "sendfile64") _S(74, "signalfd4") _S(75, "vmsplice") _S(76, "splice") _S(77, "tee") _S(78, "readlinkat") _S(81, "sync") _S(82, "fsync") _S(83, "fdatasync") _S(84, "sync_file_range") _S(85, "timerfd_create") _S(89, "acct") _S(90, "capget") _S(91, "capset") _S(92, "personality") _S(93, "exit") _S(94, "exit_group") _S(95, "waitid") _S(96, "set_tid_address") _S(97, "unshare") _S(99, "set_robust_list") _S(100, "get_robust_list") _S(102, "getitimer") _S(103, "setitimer") _S(104, "kexec_load") _S(105, "init_module") _S(106, "delete_module") _S(107, "timer_create") _S(109, "timer_getoverrun") _S(111, "timer_delete") _S(116, "syslog") _S(117, "ptrace") _S(118, "sched_setparam") _S(119, "sched_setscheduler") _S(120, "sched_getscheduler") _S(121, "sched_getparam") _S(122, "sched_setaffinity") _S(123, "sched_getaffinity") _S(124, "sched_yield") _S(125, "sched_get_priority_max") _S(126, "sched_get_priority_min") _S(128, "restart_syscall") _S(129, "kill") _S(130, "tkill") _S(131, "tgkill") _S(132, "sigaltstack") _S(133, "rt_sigsuspend") _S(134, "rt_sigaction") _S(135, "rt_sigprocmask") _S(136, "rt_sigpending") _S(138, "rt_sigqueueinfo") _S(139, "rt_sigreturn") _S(140, "setpriority") _S(141, "getpriority") _S(142, "reboot") _S(143, "setregid") _S(144, "setgid") _S(145, "setreuid") _S(146, "setuid") _S(147, "setresuid") _S(148, "getresuid") _S(149, "setresgid") _S(150, "getresgid") _S(151, "setfsuid") _S(152, "setfsgid") _S(153, "times") _S(154, "setpgid") _S(155, "getpgid") _S(156, "getsid") _S(157, "setsid") _S(158, "getgroups") _S(159, "setgroups") _S(160, "uname") _S(161, "sethostname") _S(162, "setdomainname") _S(165, "getrusage") _S(166, "umask") _S(167, "prctl") _S(168, "getcpu") _S(172, "getpid") _S(173, "getppid") _S(174, "getuid") _S(175, "geteuid") _S(176, "getgid") _S(177, "getegid") _S(178, "gettid") _S(179, "sysinfo") _S(180, "mq_open") _S(181, "mq_unlink") _S(184, "mq_notify") _S(185, "mq_getsetattr") _S(186, "msgget") _S(187, "msgctl") _S(188, "msgrcv") _S(189, "msgsnd") _S(190, "semget") _S(191, "semctl") _S(193, "semop") _S(194, "shmget") _S(195, "shmctl") _S(196, "shmat") _S(197, "shmdt") _S(198, "socket") _S(199, "socketpair") _S(200, "bind") _S(201, "listen") _S(202, "accept") _S(203, "connect") _S(204, "getsockname") _S(205, "getpeername") _S(206, "sendto") _S(207, "recvfrom") _S(208, "setsockopt") _S(209, "getsockopt") _S(210, "shutdown") _S(211, "sendmsg") _S(212, "recvmsg") _S(213, "readahead") _S(214, "brk") _S(215, "munmap") _S(216, "mremap") _S(217, "add_key") _S(218, "request_key") _S(219, "keyctl") _S(220, "clone") _S(221, "execve") _S(222, "mmap2") _S(223, "fadvise64_64") _S(224, "swapon") _S(225, "swapoff") _S(226, "mprotect") _S(227, "msync") _S(228, "mlock") _S(229, "munlock") _S(230, "mlockall") _S(231, "munlockall") _S(232, "mincore") _S(233, "madvise") _S(234, "remap_file_pages") _S(235, "mbind") _S(236, "get_mempolicy") _S(237, "set_mempolicy") _S(238, "migrate_pages") _S(239, "move_pages") _S(240, "rt_tgsigqueueinfo") _S(241, "perf_event_open") _S(242, "accept4") _S(258, "riscv_hwprobe") _S(259, "riscv_flush_icache") _S(261, "prlimit64") _S(262, "fanotify_init") _S(263, "fanotify_mark") _S(264, "name_to_handle_at") _S(265, "open_by_handle_at") _S(267, "syncfs") _S(268, "setns") _S(269, "sendmmsg") _S(270, "process_vm_readv") _S(271, "process_vm_writev") _S(272, "kcmp") _S(273, "finit_module") _S(274, "sched_setattr") _S(275, "sched_getattr") _S(276, "renameat2") _S(277, "seccomp") _S(278, "getrandom") _S(279, "memfd_create") _S(280, "bpf") _S(281, "execveat") _S(282, "userfaultfd") _S(283, "membarrier") _S(284, "mlock2") _S(285, "copy_file_range") _S(286, "preadv2") _S(287, "pwritev2") _S(288, "pkey_mprotect") _S(289, "pkey_alloc") _S(290, "pkey_free") _S(291, "statx") _S(293, "rseq") _S(294, "kexec_file_load") _S(403, "clock_gettime64") _S(404, "clock_settime64") _S(405, "clock_adjtime64") _S(406, "clock_getres_time64") _S(407, "clock_nanosleep_time64") _S(408, "timer_gettime64") _S(409, "timer_settime64") _S(410, "timerfd_gettime64") _S(411, "timerfd_settime64") _S(412, "utimensat_time64") _S(413, "pselect6_time64") _S(414, "ppoll_time64") _S(416, "io_pgetevents_time64") _S(417, "recvmmsg_time64") _S(418, "mq_timedsend_time64") _S(419, "mq_timedreceive_time64") _S(420, "semtimedop_time64") _S(421, "rt_sigtimedwait_time64") _S(422, "futex_time64") _S(423, "sched_rr_get_interval_time64") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/riscv64_table.h000066400000000000000000000171011501761310600202040ustar00rootroot00000000000000/* riscv64_table.h -- * Copyright 2024 Rivos Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * David Abdurachmanov */ _S(0, "io_setup") _S(1, "io_destroy") _S(2, "io_submit") _S(3, "io_cancel") _S(4, "io_getevents") _S(5, "setxattr") _S(6, "lsetxattr") _S(7, "fsetxattr") _S(8, "getxattr") _S(9, "lgetxattr") _S(10, "fgetxattr") _S(11, "listxattr") _S(12, "llistxattr") _S(13, "flistxattr") _S(14, "removexattr") _S(15, "lremovexattr") _S(16, "fremovexattr") _S(17, "getcwd") _S(18, "lookup_dcookie") _S(19, "eventfd2") _S(20, "epoll_create1") _S(21, "epoll_ctl") _S(22, "epoll_pwait") _S(23, "dup") _S(24, "dup3") _S(25, "fcntl") _S(26, "inotify_init1") _S(27, "inotify_add_watch") _S(28, "inotify_rm_watch") _S(29, "ioctl") _S(30, "ioprio_set") _S(31, "ioprio_get") _S(32, "flock") _S(33, "mknodat") _S(34, "mkdirat") _S(35, "unlinkat") _S(36, "symlinkat") _S(37, "linkat") _S(39, "umount2") _S(40, "mount") _S(41, "pivot_root") _S(42, "nfsservctl") _S(43, "statfs") _S(44, "fstatfs") _S(45, "truncate") _S(46, "ftruncate") _S(47, "fallocate") _S(48, "faccessat") _S(49, "chdir") _S(50, "fchdir") _S(51, "chroot") _S(52, "fchmod") _S(53, "fchmodat") _S(54, "fchownat") _S(55, "fchown") _S(56, "openat") _S(57, "close") _S(58, "vhangup") _S(59, "pipe2") _S(60, "quotactl") _S(61, "getdents64") _S(62, "lseek") _S(63, "read") _S(64, "write") _S(65, "readv") _S(66, "writev") _S(67, "pread64") _S(68, "pwrite64") _S(69, "preadv") _S(70, "pwritev") _S(71, "sendfile") _S(72, "pselect6") _S(73, "ppoll") _S(74, "signalfd4") _S(75, "vmsplice") _S(76, "splice") _S(77, "tee") _S(78, "readlinkat") _S(79, "newfstatat") _S(80, "fstat") _S(81, "sync") _S(82, "fsync") _S(83, "fdatasync") _S(84, "sync_file_range") _S(85, "timerfd_create") _S(86, "timerfd_settime") _S(87, "timerfd_gettime") _S(88, "utimensat") _S(89, "acct") _S(90, "capget") _S(91, "capset") _S(92, "personality") _S(93, "exit") _S(94, "exit_group") _S(95, "waitid") _S(96, "set_tid_address") _S(97, "unshare") _S(98, "futex") _S(99, "set_robust_list") _S(100, "get_robust_list") _S(101, "nanosleep") _S(102, "getitimer") _S(103, "setitimer") _S(104, "kexec_load") _S(105, "init_module") _S(106, "delete_module") _S(107, "timer_create") _S(108, "timer_gettime") _S(109, "timer_getoverrun") _S(110, "timer_settime") _S(111, "timer_delete") _S(112, "clock_settime") _S(113, "clock_gettime") _S(114, "clock_getres") _S(115, "clock_nanosleep") _S(116, "syslog") _S(117, "ptrace") _S(118, "sched_setparam") _S(119, "sched_setscheduler") _S(120, "sched_getscheduler") _S(121, "sched_getparam") _S(122, "sched_setaffinity") _S(123, "sched_getaffinity") _S(124, "sched_yield") _S(125, "sched_get_priority_max") _S(126, "sched_get_priority_min") _S(127, "sched_rr_get_interval") _S(128, "restart_syscall") _S(129, "kill") _S(130, "tkill") _S(131, "tgkill") _S(132, "sigaltstack") _S(133, "rt_sigsuspend") _S(134, "rt_sigaction") _S(135, "rt_sigprocmask") _S(136, "rt_sigpending") _S(137, "rt_sigtimedwait") _S(138, "rt_sigqueueinfo") _S(139, "rt_sigreturn") _S(140, "setpriority") _S(141, "getpriority") _S(142, "reboot") _S(143, "setregid") _S(144, "setgid") _S(145, "setreuid") _S(146, "setuid") _S(147, "setresuid") _S(148, "getresuid") _S(149, "setresgid") _S(150, "getresgid") _S(151, "setfsuid") _S(152, "setfsgid") _S(153, "times") _S(154, "setpgid") _S(155, "getpgid") _S(156, "getsid") _S(157, "setsid") _S(158, "getgroups") _S(159, "setgroups") _S(160, "uname") _S(161, "sethostname") _S(162, "setdomainname") _S(163, "getrlimit") _S(164, "setrlimit") _S(165, "getrusage") _S(166, "umask") _S(167, "prctl") _S(168, "getcpu") _S(169, "gettimeofday") _S(170, "settimeofday") _S(171, "adjtimex") _S(172, "getpid") _S(173, "getppid") _S(174, "getuid") _S(175, "geteuid") _S(176, "getgid") _S(177, "getegid") _S(178, "gettid") _S(179, "sysinfo") _S(180, "mq_open") _S(181, "mq_unlink") _S(182, "mq_timedsend") _S(183, "mq_timedreceive") _S(184, "mq_notify") _S(185, "mq_getsetattr") _S(186, "msgget") _S(187, "msgctl") _S(188, "msgrcv") _S(189, "msgsnd") _S(190, "semget") _S(191, "semctl") _S(192, "semtimedop") _S(193, "semop") _S(194, "shmget") _S(195, "shmctl") _S(196, "shmat") _S(197, "shmdt") _S(198, "socket") _S(199, "socketpair") _S(200, "bind") _S(201, "listen") _S(202, "accept") _S(203, "connect") _S(204, "getsockname") _S(205, "getpeername") _S(206, "sendto") _S(207, "recvfrom") _S(208, "setsockopt") _S(209, "getsockopt") _S(210, "shutdown") _S(211, "sendmsg") _S(212, "recvmsg") _S(213, "readahead") _S(214, "brk") _S(215, "munmap") _S(216, "mremap") _S(217, "add_key") _S(218, "request_key") _S(219, "keyctl") _S(220, "clone") _S(221, "execve") _S(222, "mmap") _S(223, "fadvise64") _S(224, "swapon") _S(225, "swapoff") _S(226, "mprotect") _S(227, "msync") _S(228, "mlock") _S(229, "munlock") _S(230, "mlockall") _S(231, "munlockall") _S(232, "mincore") _S(233, "madvise") _S(234, "remap_file_pages") _S(235, "mbind") _S(236, "get_mempolicy") _S(237, "set_mempolicy") _S(238, "migrate_pages") _S(239, "move_pages") _S(240, "rt_tgsigqueueinfo") _S(241, "perf_event_open") _S(242, "accept4") _S(243, "recvmmsg") _S(258, "riscv_hwprobe") _S(259, "riscv_flush_icache") _S(260, "wait4") _S(261, "prlimit64") _S(262, "fanotify_init") _S(263, "fanotify_mark") _S(264, "name_to_handle_at") _S(265, "open_by_handle_at") _S(266, "clock_adjtime") _S(267, "syncfs") _S(268, "setns") _S(269, "sendmmsg") _S(270, "process_vm_readv") _S(271, "process_vm_writev") _S(272, "kcmp") _S(273, "finit_module") _S(274, "sched_setattr") _S(275, "sched_getattr") _S(276, "renameat2") _S(277, "seccomp") _S(278, "getrandom") _S(279, "memfd_create") _S(280, "bpf") _S(281, "execveat") _S(282, "userfaultfd") _S(283, "membarrier") _S(284, "mlock2") _S(285, "copy_file_range") _S(286, "preadv2") _S(287, "pwritev2") _S(288, "pkey_mprotect") _S(289, "pkey_alloc") _S(290, "pkey_free") _S(291, "statx") _S(292, "io_pgetevents") _S(293, "rseq") _S(294, "kexec_file_load") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/s390_table.h000066400000000000000000000240051501761310600174030ustar00rootroot00000000000000/* s390_table.h -- 32 bit * Copyright 2005-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(1, "exit") _S(2, "fork") _S(3, "read") _S(4, "write") _S(5, "open") _S(6, "close") _S(7, "restart_syscall") _S(8, "creat") _S(9, "link") _S(10, "unlink") _S(11, "execve") _S(12, "chdir") _S(13, "time") _S(14, "mknod") _S(15, "chmod") _S(16, "lchown") _S(19, "lseek") _S(20, "getpid") _S(21, "mount") _S(22, "umount") _S(23, "setuid") _S(24, "getuid") _S(25, "stime") _S(26, "ptrace") _S(27, "alarm") _S(29, "pause") _S(30, "utime") _S(33, "access") _S(34, "nice") _S(36, "sync") _S(37, "kill") _S(38, "rename") _S(39, "mkdir") _S(40, "rmdir") _S(41, "dup") _S(42, "pipe") _S(43, "times") _S(45, "brk") _S(46, "setgid") _S(47, "getgid") _S(48, "signal") _S(49, "geteuid") _S(50, "getegid") _S(51, "acct") _S(52, "umount2") _S(54, "ioctl") _S(55, "fcntl") _S(57, "setpgid") _S(60, "umask") _S(61, "chroot") _S(62, "ustat") _S(63, "dup2") _S(64, "getppid") _S(65, "getpgrp") _S(66, "setsid") _S(67, "sigaction") _S(70, "setreuid") _S(71, "setregid") _S(72, "sigsuspend") _S(73, "sigpending") _S(74, "sethostname") _S(75, "setrlimit") _S(76, "getrlimit") _S(77, "getrusage") _S(78, "gettimeofday") _S(79, "settimeofday") _S(80, "getgroups") _S(81, "setgroups") _S(83, "symlink") _S(85, "readlink") _S(86, "uselib") _S(87, "swapon") _S(88, "reboot") _S(89, "readdir") _S(90, "mmap") _S(91, "munmap") _S(92, "truncate") _S(93, "ftruncate") _S(94, "fchmod") _S(95, "fchown") _S(96, "getpriority") _S(97, "setpriority") _S(99, "statfs") _S(100, "fstatfs") _S(101, "ioperm") _S(102, "socketcall") _S(103, "syslog") _S(104, "setitimer") _S(105, "getitimer") _S(106, "stat") _S(107, "lstat") _S(108, "fstat") _S(110, "lookup_dcookie") _S(111, "vhangup") _S(112, "idle") _S(114, "wait4") _S(115, "swapoff") _S(116, "sysinfo") _S(117, "ipc") _S(118, "fsync") _S(119, "sigreturn") _S(120, "clone") _S(121, "setdomainname") _S(122, "uname") _S(124, "adjtimex") _S(125, "mprotect") _S(126, "sigprocmask") _S(127, "create_module") _S(128, "init_module") _S(129, "delete_module") _S(130, "get_kernel_syms") _S(131, "quotactl") _S(132, "getpgid") _S(133, "fchdir") _S(134, "bdflush") _S(135, "sysfs") _S(136, "personality") _S(137, "afs_syscall") _S(138, "setfsuid") _S(139, "setfsgid") _S(140, "_llseek") _S(141, "getdents") _S(142, "_newselect") _S(143, "flock") _S(144, "msync") _S(145, "readv") _S(146, "writev") _S(147, "getsid") _S(148, "fdatasync") _S(149, "_sysctl") _S(150, "mlock") _S(151, "munlock") _S(152, "mlockall") _S(153, "munlockall") _S(154, "sched_setparam") _S(155, "sched_getparam") _S(156, "sched_setscheduler") _S(157, "sched_getscheduler") _S(158, "sched_yield") _S(159, "sched_get_priority_max") _S(160, "sched_get_priority_min") _S(161, "sched_rr_get_interval") _S(162, "nanosleep") _S(163, "mremap") _S(164, "setresuid") _S(165, "getresuid") _S(167, "query_module") _S(168, "poll") _S(169, "nfsservctl") _S(170, "setresgid") _S(171, "getresgid") _S(172, "prctl") _S(173, "rt_sigreturn") _S(174, "rt_sigaction") _S(175, "rt_sigprocmask") _S(176, "rt_sigpending") _S(177, "rt_sigtimedwait") _S(178, "rt_sigqueueinfo") _S(179, "rt_sigsuspend") _S(180, "pread") _S(181, "pwrite") _S(182, "chown") _S(183, "getcwd") _S(184, "capget") _S(185, "capset") _S(186, "sigaltstack") _S(187, "sendfile") _S(188, "getpmsg") _S(189, "putpmsg") _S(190, "vfork") _S(191, "ugetrlimit") _S(192, "mmap2") _S(193, "truncate64") _S(194, "ftruncate64") _S(195, "stat64") _S(196, "lstat64") _S(197, "fstat64") _S(198, "lchown32") _S(199, "getuid32") _S(200, "getgid32") _S(201, "geteuid32") _S(202, "getegid32") _S(203, "setreuid32") _S(204, "setregid32") _S(205, "getgroups32") _S(206, "setgroups32") _S(207, "fchown32") _S(208, "setresuid32") _S(209, "getresuid32") _S(210, "setresgid32") _S(211, "getresgid32") _S(212, "chown32") _S(213, "setuid32") _S(214, "setgid32") _S(215, "setfsuid32") _S(216, "setfsgid32") _S(217, "pivot_root") _S(218, "mincore") _S(219, "madvise") _S(220, "getdents64") _S(221, "fcntl64") _S(222, "readahead") _S(223, "sendfile64") _S(224, "setxattr") _S(225, "lsetxattr") _S(226, "fsetxattr") _S(227, "getxattr") _S(228, "lgetxattr") _S(229, "fgetxattr") _S(230, "listxattr") _S(231, "llistxattr") _S(232, "flistxattr") _S(233, "removexattr") _S(234, "lremovexattr") _S(235, "fremovexattr") _S(236, "gettid") _S(237, "tkill") _S(238, "futex") _S(239, "sched_setaffinity") _S(240, "sched_getaffinity") _S(241, "tgkill") //_S(242, "") _S(243, "io_setup") _S(244, "io_destroy") _S(245, "io_getevents") _S(246, "io_submit") _S(247, "io_cancel") _S(248, "exit_group") _S(249, "epoll_create") _S(250, "epoll_ctl") _S(251, "epoll_wait") _S(252, "set_tid_address") _S(253, "fadvise64") _S(254, "timer_create") _S(255, "timer_settime") _S(256, "timer_gettime") _S(257, "timer_getoverrun") _S(258, "timer_delete") _S(259, "clock_settime") _S(260, "clock_gettime") _S(261, "clock_getres") _S(262, "clock_nanosleep") //_S(263, "") _S(264, "fadvise64_64") _S(265, "statfs64") _S(266, "fstatfs64") _S(267, "remap_file_pages") _S(268, "mbind") _S(269, "get_mempolicy") _S(270, "set_mempolicy") _S(271, "mq_open") _S(272, "mq_unlink") _S(273, "mq_timedsend") _S(274, "mq_timedreceive") _S(275, "mq_notify") _S(276, "mq_getsetattr") _S(277, "kexec_load") _S(278, "add_key") _S(279, "request_key") _S(280, "keyctl") _S(281, "waitid") _S(282, "ioprio_set") _S(283, "ioprio_get") _S(284, "inotify_init") _S(285, "inotify_add_watch") _S(286, "inotify_rm_watch") _S(287, "migrate_pages") _S(288, "openat") _S(289, "mkdirat") _S(290, "mknodat") _S(291, "fchownat") _S(292, "futimesat") _S(293, "fstatat64") _S(294, "unlinkat") _S(295, "renameat") _S(296, "linkat") _S(297, "symlinkat") _S(298, "readlinkat") _S(299, "fchmodat") _S(300, "faccessat") _S(301, "pselect6") _S(302, "ppoll") _S(303, "unshare") _S(304, "set_robust_list") _S(305, "get_robust_list") _S(306, "splice") _S(307, "sync_file_range") _S(308, "tee") _S(309, "vmsplice") _S(310, "move_pages") _S(311, "getcpu") _S(312, "epoll_pwait") _S(313, "utimes") _S(314, "fallocate") _S(315, "utimensat") _S(316, "signalfd") _S(317, "timerfd") _S(318, "eventfd") _S(319, "timerfd_create") _S(320, "timerfd_settime") _S(321, "timerfd_gettime") _S(322, "signalfd4") _S(323, "eventfd2") _S(324, "inotify_init1") _S(325, "pipe2") _S(326, "dup3") _S(327, "epoll_create1") _S(328, "preadv") _S(329, "pwritev") _S(330, "rt_tgsigqueueinfo") _S(331, "perf_event_open") _S(332, "fanotify_init") _S(333, "fanotify_mark") _S(334, "prlimit64") _S(335, "name_to_handle_at") _S(336, "open_by_handle_at") _S(337, "clock_adjtime") _S(338, "syncfs") _S(339, "setns") _S(340, "process_vm_readv") _S(341, "process_vm_writev") _S(342, "s390_runtime_instr") _S(343, "kcmp") _S(344, "finit_module") _S(345, "sched_setattr") _S(346, "sched_getattr") _S(347, "renameat2") _S(348, "seccomp") _S(349, "getrandom") _S(350, "memfd_create") _S(351, "bpf") _S(352, "s390_pci_mmio_write") _S(353, "s390_pci_mmio_read") _S(354, "execveat") _S(355, "userfaultfd") _S(356, "membarrier") _S(357, "recvmmsg") _S(358, "sendmmsg") _S(359, "socket") _S(360, "socketpair") _S(361, "bind") _S(362, "connect") _S(363, "listen") _S(364, "accept4") _S(365, "getsockopt") _S(366, "setsockopt") _S(367, "getsockname") _S(368, "getpeername") _S(369, "sendto") _S(370, "sendmsg") _S(371, "recvfrom") _S(372, "recvmsg") _S(373, "shutdown") _S(374, "mlock2") _S(375, "copy_file_range") _S(376, "preadv2") _S(377, "pwritev2") _S(378, "s390_guarded_storage") _S(379, "statx") _S(380, "s390_sthyi") _S(381, "kexec_file_load") _S(382, "io_pgetevents") _S(383, "rseq") _S(384, "pkey_mprotect") _S(385, "pkey_alloc") _S(386, "pkey_free") _S(393, "semget") _S(394, "semctl") _S(395, "shmget") _S(396, "shmctl") _S(397, "shmat") _S(398, "shmdt") _S(399, "msgget") _S(400, "msgsnd") _S(401, "msgrcv") _S(402, "msgctl") _S(403, "clock_gettime64") _S(404, "clock_settime64") _S(405, "clock_adjtime64") _S(406, "clock_getres_time64") _S(407, "clock_nanosleep_time64") _S(408, "timer_gettime64") _S(409, "timer_settime64") _S(410, "timerfd_gettime64") _S(411, "timerfd_settime64") _S(412, "utimensat_time64") _S(413, "pselect6_time64") _S(414, "ppoll_time64") _S(416, "io_pgetevents_time64") _S(417, "recvmmsg_time64") _S(418, "mq_timedsend_time64") _S(419, "mq_timedreceive_time64") _S(420, "semtimedop_time64") _S(421, "rt_sigtimedwait_time64") _S(422, "futex_time64") _S(423, "sched_rr_get_interval_time64") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/s390x_table.h000066400000000000000000000214371501761310600176010ustar00rootroot00000000000000/* s390x_table.h -- 64 bit * Copyright 2005-06,2008-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(1, "exit") _S(2, "fork") _S(3, "read") _S(4, "write") _S(5, "open") _S(6, "close") _S(7, "restart_syscall") _S(8, "creat") _S(9, "link") _S(10, "unlink") _S(11, "execve") _S(12, "chdir") _S(14, "mknod") _S(15, "chmod") _S(19, "lseek") _S(20, "getpid") _S(21, "mount") _S(22, "umount") _S(26, "ptrace") _S(27, "alarm") _S(29, "pause") _S(30, "utime") _S(33, "access") _S(34, "nice") _S(36, "sync") _S(37, "kill") _S(38, "rename") _S(39, "mkdir") _S(40, "rmdir") _S(41, "dup") _S(42, "pipe") _S(43, "times") _S(45, "brk") _S(48, "signal") _S(51, "acct") _S(52, "umount2") _S(54, "ioctl") _S(55, "fcntl") _S(57, "setpgid") _S(60, "umask") _S(61, "chroot") _S(62, "ustat") _S(63, "dup2") _S(64, "getppid") _S(65, "getpgrp") _S(66, "setsid") _S(67, "sigaction") _S(72, "sigsuspend") _S(73, "sigpending") _S(74, "sethostname") _S(75, "setrlimit") _S(77, "getrusage") _S(78, "gettimeofday") _S(79, "settimeofday") _S(83, "symlink") _S(85, "readlink") _S(86, "uselib") _S(87, "swapon") _S(88, "reboot") _S(89, "readdir") _S(90, "mmap") _S(91, "munmap") _S(92, "truncate") _S(93, "ftruncate") _S(94, "fchmod") _S(96, "getpriority") _S(97, "setpriority") _S(99, "statfs") _S(100, "fstatfs") _S(102, "socketcall") _S(103, "syslog") _S(104, "setitimer") _S(105, "getitimer") _S(106, "stat") _S(107, "lstat") _S(108, "fstat") _S(110, "lookup_dcookie") _S(111, "vhangup") _S(112, "idle") _S(114, "wait4") _S(115, "swapoff") _S(116, "sysinfo") _S(117, "ipc") _S(118, "fsync") _S(119, "sigreturn") _S(120, "clone") _S(121, "setdomainname") _S(122, "uname") _S(124, "adjtimex") _S(125, "mprotect") _S(126, "sigprocmask") _S(127, "create_module") _S(128, "init_module") _S(129, "delete_module") _S(130, "get_kernel_syms") _S(131, "quotactl") _S(132, "getpgid") _S(133, "fchdir") _S(134, "bdflush") _S(135, "sysfs") _S(136, "personality") _S(137, "afs_syscall") _S(141, "getdents") _S(142, "select") _S(143, "flock") _S(144, "msync") _S(145, "readv") _S(146, "writev") _S(147, "getsid") _S(148, "fdatasync") _S(149, "_sysctl") _S(150, "mlock") _S(151, "munlock") _S(152, "mlockall") _S(153, "munlockall") _S(154, "sched_setparam") _S(155, "sched_getparam") _S(156, "sched_setscheduler") _S(157, "sched_getscheduler") _S(158, "sched_yield") _S(159, "sched_get_priority_max") _S(160, "sched_get_priority_min") _S(161, "sched_rr_get_interval") _S(162, "nanosleep") _S(163, "mremap") _S(167, "query_module") _S(168, "poll") _S(169, "nfsservctl") _S(172, "prctl") _S(173, "rt_sigreturn") _S(174, "rt_sigaction") _S(175, "rt_sigprocmask") _S(176, "rt_sigpending") _S(177, "rt_sigtimedwait") _S(178, "rt_sigqueueinfo") _S(179, "rt_sigsuspend") _S(180, "pread") _S(181, "pwrite") _S(183, "getcwd") _S(184, "capget") _S(185, "capset") _S(186, "sigaltstack") _S(187, "sendfile") _S(188, "getpmsg") _S(189, "putpmsg") _S(190, "vfork") _S(191, "getrlimit") _S(198, "lchown") _S(199, "getuid") _S(200, "getgid") _S(201, "geteuid") _S(202, "getegid") _S(203, "setreuid") _S(204, "setregid") _S(205, "getgroups") _S(206, "setgroups") _S(207, "fchown") _S(208, "setresuid") _S(209, "getresuid") _S(210, "setresgid") _S(211, "getresgid") _S(212, "chown") _S(213, "setuid") _S(214, "setgid") _S(215, "setfsuid") _S(216, "setfsgid") _S(217, "pivot_root") _S(218, "mincore") _S(219, "madvise") _S(220, "getdents64") _S(222, "readahead") _S(224, "setxattr") _S(225, "lsetxattr") _S(226, "fsetxattr") _S(227, "getxattr") _S(228, "lgetxattr") _S(229, "fgetxattr") _S(230, "listxattr") _S(231, "llistxattr") _S(232, "flistxattr") _S(233, "removexattr") _S(234, "lremovexattr") _S(235, "fremovexattr") _S(236, "gettid") _S(237, "tkill") _S(238, "futex") _S(239, "sched_setaffinity") _S(240, "sched_getaffinity") _S(241, "tgkill") _S(243, "io_setup") _S(244, "io_destroy") _S(245, "io_getevents") _S(246, "io_submit") _S(247, "io_cancel") _S(248, "exit_group") _S(249, "epoll_create") _S(250, "epoll_ctl") _S(251, "epoll_wait") _S(252, "set_tid_address") _S(253, "fadvise64") _S(254, "timer_create") _S(255, "timer_settime") _S(256, "timer_gettime") _S(257, "timer_getoverrun") _S(258, "timer_delete") _S(259, "clock_settime") _S(260, "clock_gettime") _S(261, "clock_getres") _S(262, "clock_nanosleep") _S(265, "statfs64") _S(266, "fstatfs64") _S(267, "remap_file_pages") _S(268, "mbind") _S(269, "get_mempolicy") _S(270, "set_mempolicy") _S(271, "mq_open") _S(272, "mq_unlink") _S(273, "mq_timedsend") _S(274, "mq_timedreceive") _S(275, "mq_notify") _S(276, "mq_getsetattr") _S(277, "kexec_load") _S(278, "add_key") _S(279, "request_key") _S(280, "keyctl") _S(281, "waitid") _S(282, "ioprio_set") _S(283, "ioprio_get") _S(284, "inotify_init") _S(285, "inotify_add_watch") _S(286, "inotify_rm_watch") _S(287, "migrate_pages") _S(288, "openat") _S(289, "mkdirat") _S(290, "mknodat") _S(291, "fchownat") _S(292, "futimesat") _S(293, "newfstatat") _S(294, "unlinkat") _S(295, "renameat") _S(296, "linkat") _S(297, "symlinkat") _S(298, "readlinkat") _S(299, "fchmodat") _S(300, "faccessat") _S(301, "pselect6") _S(302, "ppoll") _S(303, "unshare") _S(304, "set_robust_list") _S(305, "get_robust_list") _S(306, "splice") _S(307, "sync_file_range") _S(308, "tee") _S(309, "vmsplice") _S(310, "move_pages") _S(311, "getcpu") _S(312, "epoll_pwait") _S(313, "utimes") _S(314, "fallocate") _S(315, "utimensat") _S(316, "signalfd") _S(317, "timerfd") _S(318, "eventfd") _S(319, "timerfd_create") _S(320, "timerfd_settime") _S(321, "timerfd_gettime") _S(322, "signalfd4") _S(323, "eventfd2") _S(324, "inotify_init1") _S(325, "pipe2") _S(326, "dup3") _S(327, "epoll_create1") _S(328, "preadv") _S(329, "pwritev") _S(330, "rt_tgsigqueueinfo") _S(331, "perf_event_open") _S(332, "fanotify_init") _S(333, "fanotify_mark") _S(334, "prlimit64") _S(335, "name_to_handle_at") _S(336, "open_by_handle_at") _S(337, "clock_adjtime") _S(338, "syncfs") _S(339, "setns") _S(340, "process_vm_readv") _S(341, "process_vm_writev") _S(342, "s390_runtime_instr") _S(343, "kcmp") _S(344, "finit_module") _S(345, "sched_setattr") _S(346, "sched_getattr") _S(347, "renameat2") _S(348, "seccomp") _S(349, "getrandom") _S(350, "memfd_create") _S(351, "bpf") _S(352, "s390_pci_mmio_write") _S(353, "s390_pci_mmio_read") _S(354, "execveat") _S(355, "userfaultfd") _S(356, "membarrier") _S(357, "recvmmsg") _S(358, "sendmmsg") _S(359, "socket") _S(360, "socketpair") _S(361, "bind") _S(362, "connect") _S(363, "listen") _S(364, "accept4") _S(365, "getsockopt") _S(366, "setsockopt") _S(367, "getsockname") _S(368, "getpeername") _S(369, "sendto") _S(370, "sendmsg") _S(371, "recvfrom") _S(372, "recvmsg") _S(373, "shutdown") _S(374, "mlock2") _S(375, "copy_file_range") _S(376, "preadv2") _S(377, "pwritev2") _S(378, "s390_guarded_storage") _S(379, "statx") _S(380, "s390_sthyi") _S(381, "kexec_file_load") _S(382, "io_pgetevents") _S(383, "rseq") _S(384, "pkey_mprotect") _S(385, "pkey_alloc") _S(386, "pkey_free") _S(392, "semtimedop") _S(393, "semget") _S(394, "semctl") _S(395, "shmget") _S(396, "shmctl") _S(397, "shmat") _S(398, "shmdt") _S(399, "msgget") _S(400, "msgsnd") _S(401, "msgrcv") _S(402, "msgctl") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/lib/syscall-update.txt000066400000000000000000000033061501761310600210610ustar00rootroot00000000000000The place where syscall information is gathered is: arch/arm/tools/syscall.tbl arch/arm/include/uapi/asm/unistd.h (unused?) include/uapi/asm-generic/unistd.h (aarch64) arch/powerpc/kernel/syscalls/syscall.tbl arch/s390/kernel/syscalls/syscall.tbl arch/x86/entry/syscalls/syscall_32.tbl arch/x86/entry/syscalls/syscall_64.tbl include/uapi/asm-generic/unistd.h (riscv32, riscv64) For src/ausearch-lookup.c: Inspect include/linux/net.h for socketcall updates Inspect include/linux/ipc.h for ipccall updates For adding new arches, the following might be useful to get a first pass file: cat unistd.h | grep '^#define __NR_' | tr -d ')' | tr 'NR+' ' ' | awk '{ printf "_S(%s, \"%s\")\n", $6, $3 }; ' On newer kernels (4.19+): cat unistd.h | grep '^#define __NR_' | sed 's/__NR_//g' | awk '{ printf "_S(%s, \"%s\")\n", $3, $2 }; ' it will still need hand editing Alternative would be to use https://pypi.org/project/system-calls/ Python pacakge. The latest version is available here: https://github.com/hrw/syscalls-table Another place to find syscalls (not incl. riscv yet) is in GDB: https://github.com/bminor/binutils-gdb/tree/master/gdb/syscalls For example (system-calls 5.19.0): #!/usr/bin/python3 import system_calls import sys syscalls = system_calls.syscalls() table = {} for syscall_name in syscalls.names(): num = None try: num = syscalls.get(syscall_name, "riscv64") except system_calls.NotSupportedSystemCall: pass if num is not None: if num in table: print("This is bad!") sys.exit(1) table[num] = syscall_name for key, value in sorted(table.items(), key=lambda item: int(item[0])): print("_S({}, \"{}\")".format(key, value)) audit-userspace-4.0.5/lib/test/000077500000000000000000000000001501761310600163435ustar00rootroot00000000000000audit-userspace-4.0.5/lib/test/Makefile.am000066400000000000000000000022011501761310600203720ustar00rootroot00000000000000# Copyright 2008 Red Hat Inc. # All Rights Reserved. # # 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # Authors: # Miloslav Trmač # AM_CPPFLAGS = -I${top_srcdir}/lib check_PROGRAMS = lookup_test fgets_test TESTS = $(check_PROGRAMS) lookup_test_LDADD = ${top_builddir}/lib/libaudit.la lookup_test_DEPENDENCIES = ${top_builddir}/lib/libaudit.la fgets_test_LDADD = ${top_builddir}/lib/libaudit.la fgets_test_DEPENDENCIES = ${top_builddir}/lib/libaudit.la audit-userspace-4.0.5/lib/test/fgets_test.c000066400000000000000000000075371501761310600206720ustar00rootroot00000000000000// test-audit-fgets.c #include #include #include #include #include #include "audit-fgets.c" static void test_simple_line(void) { int fds[2]; char buf[16]; assert(pipe(fds) == 0); audit_fgets_clear(); // nothing in buffer yet assert(audit_fgets_more(sizeof(buf)) == 0); assert(audit_fgets_eof() == 0); // feed exactly one line and close const char *input = "hello\n"; assert(write(fds[1], input, strlen(input))); close(fds[1]); // now we should see a complete line assert(audit_fgets_more(sizeof(buf)) == 0); int len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 6); assert(strcmp(buf, "hello\n") == 0); assert(audit_fgets_more(sizeof(buf)) == 0); assert(audit_fgets_eof() == 0); // next call: see EOF, no data len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 0); assert(audit_fgets_eof() == 1); close(fds[0]); } static void test_multiple_lines(void) { int fds[2]; char buf[16]; assert(pipe(fds) == 0); audit_fgets_clear(); const char *input = "one\n two\n"; assert(write(fds[1], input, strlen(input))); close(fds[1]); // first line int len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 4); assert(strcmp(buf, "one\n") == 0); // leftover " two\n" → there's a newline pending assert(audit_fgets_more(sizeof(buf)) == 1); // second line len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 5); assert(strcmp(buf, " two\n") == 0); // now buffer empties, EOF len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 0); assert(audit_fgets_eof() == 1); assert(audit_fgets_more(sizeof(buf)) == 0); close(fds[0]); } static void test_partial_line(void) { int fds[2]; char buf[16]; assert(pipe(fds) == 0); audit_fgets_clear(); const char *input = "partial"; // no '\n' assert(write(fds[1], input, strlen(input))); close(fds[1]); // should hand back "partial" once EOF arrives int len = audit_fgets(buf, sizeof(buf), fds[0]); /* first call buffers the data but doesn't yet see EOF */ assert(len == 0); assert(audit_fgets_eof() == 0); /* second call returns the partial line and sets EOF */ len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == (int)strlen(input)); assert(memcmp(buf, input, len) == 0); assert(audit_fgets_eof() == 1); /* further calls return 0 once drained */ len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 0); close(fds[0]); } static void test_long_line(void) { int fds[2]; char buf[10]; assert(pipe(fds) == 0); audit_fgets_clear(); // make a 20-byte 'a' line plus '\n' char input[22]; memset(input, 'a', 20); input[20] = '\n'; input[21] = '\0'; assert(write(fds[1], input, 21)); close(fds[1]); // 1) first chunk (blen=10 → blen-1=9) int len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 9); for (int i = 0; i < len; i++) assert(buf[i] == 'a'); assert(buf[len] == '\0'); // still have >9 bytes left (and no '\n' within the first 9) assert(audit_fgets_more(sizeof(buf)) == 1); // 2) second chunk: still sees newline in the remainder, // but clamps again to 9 len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 9); for (int i = 0; i < len; i++) assert(buf[i] == 'a'); assert(buf[len] == '\0'); assert(audit_fgets_more(sizeof(buf)) == 1); // 3) finally the last "aa\n" len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 3); assert(buf[0] == 'a' && buf[1] == 'a' && buf[2] == '\n'); assert(buf[3] == '\0'); /* we’ve drained the data but haven’t hit EOF yet */ assert(audit_fgets_more(sizeof(buf)) == 0); assert(audit_fgets_eof() == 0); /* one more call to drive the EOF read() == 0 */ len = audit_fgets(buf, sizeof(buf), fds[0]); assert(len == 0); assert(audit_fgets_eof() == 1); close(fds[0]); } int main(void) { test_simple_line(); test_multiple_lines(); test_partial_line(); test_long_line(); printf("audit-fgets tests: all passed\n"); return 0; } audit-userspace-4.0.5/lib/test/lookup_test.c000066400000000000000000000225021501761310600210600ustar00rootroot00000000000000/* lookup_test.c -- A test of table lookups. * Copyright 2008 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Miloslav Trmač */ #include "config.h" #include #include #include #include #include #include #include "libaudit.h" /* Number of lookups of random strings */ #define RAND_ITERATIONS 1000 /* Maximum size of randomly generated strings, including the terminating NUL. */ #define S_LEN 8 struct entry { int val; const char *s; }; #define _S(V, S) { (V), (S) }, /* Generate a random string into DEST[S_LEN]. */ static void gen_id(char *dest) { size_t i, len; assert(S_LEN >= 2); len = 1 + rand() % (S_LEN - 1); assert('A' == 0x41 && 'a' == 0x61); /* ASCII */ for (i = 0; i < len; i++) { /* Don't start with a digit, audit_name_to_msg_type() interprets those strings specially. */ do { dest[i] = 0x21 + rand() % (0x7F - 0x21); } while (i == 0 && dest[i] >= '0' && dest[i] <= '9'); } dest[i] = '\0'; } #define TEST_I2S(EXCL) \ do { \ size_t i; \ \ for (i = 0; i < sizeof(t) / sizeof(*t); i++) { \ const char *s; \ \ if (EXCL) \ continue; \ s = I2S(t[i].val); \ if (s == NULL) { \ fprintf(stderr, \ "%d -> `%s' not found\n", \ t[i].val, t[i].s); \ abort(); \ } \ if (strcmp(t[i].s, s) != 0) { \ fprintf(stderr, \ "%d -> `%s' mismatch `%s'\n", \ t[i].val, t[i].s, s); \ abort(); \ } \ } \ for (i = 0; i < RAND_ITERATIONS; i++) { \ int val; \ size_t j; \ val = rand(); \ for (j = 0; j < sizeof(t) / sizeof(*t); j++) { \ if (t[j].val == val) \ goto test_i2s_found; \ } \ assert(I2S(val) == NULL); \ test_i2s_found: \ ; \ } \ } while (0) #define TEST_S2I(ERR_VALUE) \ do { \ size_t i; \ char buf[S_LEN]; \ \ for (i = 0; i < sizeof(t) / sizeof(*t); i++) \ assert(S2I(t[i].s) == t[i].val); \ for (i = 0; i < RAND_ITERATIONS; i++) { \ /* Blindly assuming this will not generate a \ meaningful identifier. */ \ gen_id(buf); \ if (S2I(buf) != (ERR_VALUE)) { \ fprintf(stderr, \ "Unexpected match `%s'\n", \ buf); \ abort(); \ } \ } \ } while (0) #ifdef WITH_ARM static void test_arm_table(void) { static const struct entry t[] = { #include "../arm_table.h" }; printf("Testing arm_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_ARM) #define S2I(S) audit_name_to_syscall((S), MACH_ARM) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } #endif #ifdef WITH_AARCH64 static void test_aarch64_table(void) { static const struct entry t[] = { #include "../aarch64_table.h" }; printf("Testing aarch64_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_AARCH64) #define S2I(S) audit_name_to_syscall((S), MACH_AARCH64) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } #endif #ifdef WITH_RISCV static void test_riscv64_table(void) { static const struct entry t[] = { #include "../riscv64_table.h" }; printf("Testing riscv64_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_RISCV64) #define S2I(S) audit_name_to_syscall((S), MACH_RISCV64) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_riscv32_table(void) { static const struct entry t[] = { #include "../riscv32_table.h" }; printf("Testing riscv32_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_RISCV32) #define S2I(S) audit_name_to_syscall((S), MACH_RISCV32) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } #endif static void test_i386_table(void) { static const struct entry t[] = { #include "../i386_table.h" }; printf("Testing i386_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_X86) #define S2I(S) audit_name_to_syscall((S), MACH_X86) TEST_I2S(strcmp(t[i].s, "madvise1") == 0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_ppc_table(void) { static const struct entry t[] = { #include "../ppc_table.h" }; printf("Testing ppc_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_PPC) #define S2I(S) audit_name_to_syscall((S), MACH_PPC) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_s390_table(void) { static const struct entry t[] = { #include "../s390_table.h" }; printf("Testing s390_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_S390) #define S2I(S) audit_name_to_syscall((S), MACH_S390) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_s390x_table(void) { static const struct entry t[] = { #include "../s390x_table.h" }; printf("Testing s390x_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_S390X) #define S2I(S) audit_name_to_syscall((S), MACH_S390X) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_x86_64_table(void) { static const struct entry t[] = { #include "../x86_64_table.h" }; printf("Testing x86_64_table...\n"); #define I2S(I) audit_syscall_to_name((I), MACH_86_64) #define S2I(S) audit_name_to_syscall((S), MACH_86_64) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } #ifdef WITH_IO_URING static void test_uringop_table(void) { static const struct entry t[] = { #include "../uringop_table.h" }; printf("Testing uringop_table...\n"); #define I2S(I) audit_uringop_to_name((I)) #define S2I(S) audit_name_to_uringop((S)) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } #endif static void test_actiontab(void) { static const struct entry t[] = { #include "../actiontab.h" }; printf("Testing actiontab...\n"); #define I2S(I) audit_action_to_name(I) #define S2I(S) audit_name_to_action(S) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_errtab(void) { static const struct entry t[] = { #include "../errtab.h" }; printf("Testing errtab...\n"); #define I2S(I) audit_errno_to_name(I) #define S2I(S) audit_name_to_errno(S) TEST_I2S(strcmp(t[i].s, "EWOULDBLOCK") == 0 || strcmp(t[i].s, "EDEADLOCK") == 0); TEST_S2I(0); #undef I2S #undef S2I } static void test_fieldtab(void) { static const struct entry t[] = { #include "../fieldtab.h" }; printf("Testing fieldtab...\n"); #define I2S(I) audit_field_to_name(I) #define S2I(S) audit_name_to_field(S) TEST_I2S(strcmp(t[i].s, "loginuid") == 0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_flagtab(void) { static const struct entry t[] = { #include "../flagtab.h" }; printf("Testing flagtab...\n"); #define I2S(I) audit_flag_to_name(I) #define S2I(S) audit_name_to_flag(S) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_fstypetab(void) { static const struct entry t[] = { #include "../fstypetab.h" }; printf("Testing fstypetab...\n"); #define I2S(I) audit_fstype_to_name(I) #define S2I(S) audit_name_to_fstype(S) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_ftypetab(void) { static const struct entry t[] = { #include "../ftypetab.h" }; printf("Testing ftypetab...\n"); #define I2S(I) audit_ftype_to_name(I) #define S2I(S) audit_name_to_ftype(S) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_machinetab(void) { static const struct entry t[] = { #include "../machinetab.h" }; printf("Testing machinetab...\n"); #define I2S(I) audit_machine_to_name(I) #define S2I(S) audit_name_to_machine(S) TEST_I2S((t[i].s[0] == 'i' && t[i].s[1] >= '4' && t[i].s[1] <= '6' && strcmp(t[i].s + 2, "86") == 0) || (strncmp(t[i].s, "arm", 3) == 0)); TEST_S2I(-1); #undef I2S #undef S2I } static void test_msg_typetab(void) { static const struct entry t[] = { #include "../msg_typetab.h" }; printf("Testing msg_typetab...\n"); #define I2S(I) audit_msg_type_to_name(I) #define S2I(S) audit_name_to_msg_type(S) TEST_I2S(0); TEST_S2I(-1); #undef I2S #undef S2I } static void test_optab(void) { static const struct entry t[] = { #include "../optab.h" }; printf("Testing optab...\n"); #define I2S(I) audit_operator_to_symbol(I) TEST_I2S(0); #undef I2S } int main(void) { // This is only for preventing collisions in s2i tests. // If collisions are found in future, change the number. srand(3); #ifdef WITH_ARM test_arm_table(); #endif #ifdef WITH_AARCH64 test_aarch64_table(); #endif #ifdef WITH_RISCV test_riscv64_table(); test_riscv32_table(); #endif test_i386_table(); test_ppc_table(); test_s390_table(); test_s390x_table(); test_x86_64_table(); #ifdef WITH_IO_URING test_uringop_table(); #endif test_actiontab(); test_errtab(); test_fieldtab(); test_flagtab(); test_fstypetab(); test_ftypetab(); test_machinetab(); test_msg_typetab(); test_optab(); return EXIT_SUCCESS; } audit-userspace-4.0.5/lib/uringop_table.h000066400000000000000000000036511501761310600203740ustar00rootroot00000000000000/* uringop_table.h -- * Copyright 2005-24 Red Hat Inc. * All Rights Reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA * * Authors: * Richard Guy Briggs */ /* * Enums defined in include/uapi/linux/io_uring.h * Operations defined here: io_uring/opdef.c * * Note: not all ops are auditable for performance reasons. This was * discussed on the linux-audit mail list: * https://lists.linux-audit.osci.io/archives/list/linux-audit@lists.linux-audit.osci.io/thread/7VZ6IKS4XRP2UTSHURJDPH2N6LEEZG57/ * * Operations in opdef.c will have a field, audit_skip, if they are not * auditable. Any operation missing this is auditable and needs to be added. */ _S(9, "sendmsg") _S(10, "recvmsg") _S(13, "accept") _S(16, "connect") _S(17, "fallocate") _S(18, "openat") _S(19, "close") _S(28, "openat2") _S(34, "shutdown") _S(35, "renameat") _S(36, "unlinkat") _S(37, "mkdirat") _S(38, "symlinkat") _S(39, "linkat") _S(40, "msg_ring") _S(41, "fsetxattr") _S(42, "setxattr") _S(43, "fgetxattr") _S(44, "getxattr") _S(46, "uring_cmd") _S(48, "sendmsg_zc") _S(50, "waitid") _S(51, "futex_wait") _S(52, "futex_wake") _S(53, "futex_waitv") _S(54, "fixed_fd_install") _S(55, "ftruncate") _S(56, "bind") _S(57, "listen") audit-userspace-4.0.5/lib/x86_64_table.h000066400000000000000000000211121501761310600176370ustar00rootroot00000000000000/* x86_64_table.h -- * Copyright 2005-24 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ _S(0, "read") _S(1, "write") _S(2, "open") _S(3, "close") _S(4, "stat") _S(5, "fstat") _S(6, "lstat") _S(7, "poll") _S(8, "lseek") _S(9, "mmap") _S(10, "mprotect") _S(11, "munmap") _S(12, "brk") _S(13, "rt_sigaction") _S(14, "rt_sigprocmask") _S(15, "rt_sigreturn") _S(16, "ioctl") _S(17, "pread") _S(18, "pwrite") _S(19, "readv") _S(20, "writev") _S(21, "access") _S(22, "pipe") _S(23, "select") _S(24, "sched_yield") _S(25, "mremap") _S(26, "msync") _S(27, "mincore") _S(28, "madvise") _S(29, "shmget") _S(30, "shmat") _S(31, "shmctl") _S(32, "dup") _S(33, "dup2") _S(34, "pause") _S(35, "nanosleep") _S(36, "getitimer") _S(37, "alarm") _S(38, "setitimer") _S(39, "getpid") _S(40, "sendfile") _S(41, "socket") _S(42, "connect") _S(43, "accept") _S(44, "sendto") _S(45, "recvfrom") _S(46, "sendmsg") _S(47, "recvmsg") _S(48, "shutdown") _S(49, "bind") _S(50, "listen") _S(51, "getsockname") _S(52, "getpeername") _S(53, "socketpair") _S(54, "setsockopt") _S(55, "getsockopt") _S(56, "clone") _S(57, "fork") _S(58, "vfork") _S(59, "execve") _S(60, "exit") _S(61, "wait4") _S(62, "kill") _S(63, "uname") _S(64, "semget") _S(65, "semop") _S(66, "semctl") _S(67, "shmdt") _S(68, "msgget") _S(69, "msgsnd") _S(70, "msgrcv") _S(71, "msgctl") _S(72, "fcntl") _S(73, "flock") _S(74, "fsync") _S(75, "fdatasync") _S(76, "truncate") _S(77, "ftruncate") _S(78, "getdents") _S(79, "getcwd") _S(80, "chdir") _S(81, "fchdir") _S(82, "rename") _S(83, "mkdir") _S(84, "rmdir") _S(85, "creat") _S(86, "link") _S(87, "unlink") _S(88, "symlink") _S(89, "readlink") _S(90, "chmod") _S(91, "fchmod") _S(92, "chown") _S(93, "fchown") _S(94, "lchown") _S(95, "umask") _S(96, "gettimeofday") _S(97, "getrlimit") _S(98, "getrusage") _S(99, "sysinfo") _S(100, "times") _S(101, "ptrace") _S(102, "getuid") _S(103, "syslog") _S(104, "getgid") _S(105, "setuid") _S(106, "setgid") _S(107, "geteuid") _S(108, "getegid") _S(109, "setpgid") _S(110, "getppid") _S(111, "getpgrp") _S(112, "setsid") _S(113, "setreuid") _S(114, "setregid") _S(115, "getgroups") _S(116, "setgroups") _S(117, "setresuid") _S(118, "getresuid") _S(119, "setresgid") _S(120, "getresgid") _S(121, "getpgid") _S(122, "setfsuid") _S(123, "setfsgid") _S(124, "getsid") _S(125, "capget") _S(126, "capset") _S(127, "rt_sigpending") _S(128, "rt_sigtimedwait") _S(129, "rt_sigqueueinfo") _S(130, "rt_sigsuspend") _S(131, "sigaltstack") _S(132, "utime") _S(133, "mknod") _S(134, "uselib") _S(135, "personality") _S(136, "ustat") _S(137, "statfs") _S(138, "fstatfs") _S(139, "sysfs") _S(140, "getpriority") _S(141, "setpriority") _S(142, "sched_setparam") _S(143, "sched_getparam") _S(144, "sched_setscheduler") _S(145, "sched_getscheduler") _S(146, "sched_get_priority_max") _S(147, "sched_get_priority_min") _S(148, "sched_rr_get_interval") _S(149, "mlock") _S(150, "munlock") _S(151, "mlockall") _S(152, "munlockall") _S(153, "vhangup") _S(154, "modify_ldt") _S(155, "pivot_root") _S(156, "_sysctl") _S(157, "prctl") _S(158, "arch_prctl") _S(159, "adjtimex") _S(160, "setrlimit") _S(161, "chroot") _S(162, "sync") _S(163, "acct") _S(164, "settimeofday") _S(165, "mount") _S(166, "umount2") _S(167, "swapon") _S(168, "swapoff") _S(169, "reboot") _S(170, "sethostname") _S(171, "setdomainname") _S(172, "iopl") _S(173, "ioperm") _S(174, "create_module") _S(175, "init_module") _S(176, "delete_module") _S(177, "get_kernel_syms") _S(178, "query_module") _S(179, "quotactl") _S(180, "nfsservctl") _S(181, "getpmsg") _S(182, "putpmsg") _S(183, "afs_syscall") _S(184, "tuxcall") _S(185, "security") _S(186, "gettid") _S(187, "readahead") _S(188, "setxattr") _S(189, "lsetxattr") _S(190, "fsetxattr") _S(191, "getxattr") _S(192, "lgetxattr") _S(193, "fgetxattr") _S(194, "listxattr") _S(195, "llistxattr") _S(196, "flistxattr") _S(197, "removexattr") _S(198, "lremovexattr") _S(199, "fremovexattr") _S(200, "tkill") _S(201, "time") _S(202, "futex") _S(203, "sched_setaffinity") _S(204, "sched_getaffinity") _S(205, "set_thread_area") _S(206, "io_setup") _S(207, "io_destroy") _S(208, "io_getevents") _S(209, "io_submit") _S(210, "io_cancel") _S(211, "get_thread_area") _S(212, "lookup_dcookie") _S(213, "epoll_create") _S(214, "epoll_ctl_old") _S(215, "epoll_wait_old") _S(216, "remap_file_pages") _S(217, "getdents64") _S(218, "set_tid_address") _S(219, "restart_syscall") _S(220, "semtimedop") _S(221, "fadvise64") _S(222, "timer_create") _S(223, "timer_settime") _S(224, "timer_gettime") _S(225, "timer_getoverrun") _S(226, "timer_delete") _S(227, "clock_settime") _S(228, "clock_gettime") _S(229, "clock_getres") _S(230, "clock_nanosleep") _S(231, "exit_group") _S(232, "epoll_wait") _S(233, "epoll_ctl") _S(234, "tgkill") _S(235, "utimes") _S(236, "vserver") _S(237, "mbind") _S(238, "set_mempolicy") _S(239, "get_mempolicy") _S(240, "mq_open") _S(241, "mq_unlink") _S(242, "mq_timedsend") _S(243, "mq_timedreceive") _S(244, "mq_notify") _S(245, "mq_getsetattr") _S(246, "kexec_load") _S(247, "waitid") _S(248, "add_key") _S(249, "request_key") _S(250, "keyctl") _S(251, "ioprio_set") _S(252, "ioprio_get") _S(253, "inotify_init") _S(254, "inotify_add_watch") _S(255, "inotify_rm_watch") _S(256, "migrate_pages") _S(257, "openat") _S(258, "mkdirat") _S(259, "mknodat") _S(260, "fchownat") _S(261, "futimesat") _S(262, "newfstatat") _S(263, "unlinkat") _S(264, "renameat") _S(265, "linkat") _S(266, "symlinkat") _S(267, "readlinkat") _S(268, "fchmodat") _S(269, "faccessat") _S(270, "pselect6") _S(271, "ppoll") _S(272, "unshare") _S(273, "set_robust_list") _S(274, "get_robust_list") _S(275, "splice") _S(276, "tee") _S(277, "sync_file_range") _S(278, "vmsplice") _S(279, "move_pages") _S(280, "utimensat") _S(281, "epoll_pwait") _S(282, "signalfd") _S(283, "timerfd_create") _S(284, "eventfd") _S(285, "fallocate") _S(286, "timerfd_settime") _S(287, "timerfd_gettime") _S(288, "accept4") _S(289, "signalfd4") _S(290, "eventfd2") _S(291, "epoll_create1") _S(292, "dup3") _S(293, "pipe2") _S(294, "inotify_init1") _S(295, "preadv") _S(296, "pwritev") _S(297, "rt_tgsigqueueinfo") _S(298, "perf_event_open") _S(299, "recvmmsg") _S(300, "fanotify_init") _S(301, "fanotify_mark") _S(302, "prlimit64") _S(303, "name_to_handle_at") _S(304, "open_by_handle_at") _S(305, "clock_adjtime") _S(306, "syncfs") _S(307, "sendmmsg") _S(308, "setns") _S(309, "getcpu") _S(310, "process_vm_readv") _S(311, "process_vm_writev") _S(312, "kcmp") _S(313, "finit_module") _S(314, "sched_setattr") _S(315, "sched_getattr") _S(316, "renameat2") _S(317, "seccomp") _S(318, "getrandom") _S(319, "memfd_create") _S(320, "kexec_file_load") _S(321, "bpf") _S(322, "execveat") _S(323, "userfaultfd") _S(324, "membarrier") _S(325, "mlock2") _S(326, "copy_file_range") _S(327, "preadv2") _S(328, "pwritev2") _S(329, "pkey_mprotect") _S(330, "pkey_alloc") _S(331, "pkey_free") _S(332, "statx") _S(333, "io_pgetevents") _S(334, "rseq") _S(424, "pidfd_send_signal") _S(425, "io_uring_setup") _S(426, "io_uring_enter") _S(427, "io_uring_register") _S(428, "open_tree") _S(429, "move_mount") _S(430, "fsopen") _S(431, "fsconfig") _S(432, "fsmount") _S(433, "fspick") _S(434, "pidfd_open") _S(435, "clone3") _S(436, "close_range") _S(437, "openat2") _S(438, "pidfd_getfd") _S(439, "faccessat2") _S(440, "process_madvise") _S(441, "epoll_pwait2") _S(442, "mount_setattr") _S(443, "quotactl_fd") _S(444, "landlock_create_ruleset") _S(445, "landlock_add_rule") _S(446, "landlock_restrict_self") _S(447, "memfd_secret") _S(448, "process_mrelease") _S(449, "futex_waitv") _S(450, "set_mempolicy_home_node") _S(451, "cachestat") _S(452, "fchmodat2") _S(453, "map_shadow_stack") _S(454, "futex_wake") _S(455, "futex_wait") _S(456, "futex_requeue") _S(457, "statmount") _S(458, "listmount") _S(459, "lsm_get_self_attr") _S(460, "lsm_set_self_attr") _S(461, "lsm_list_modules") _S(462, "mseal") _S(463, "setxattrat") _S(464, "getxattrat") _S(465, "listxattrat") _S(466, "removexattrat") _S(467, "open_tree_attr") audit-userspace-4.0.5/m4/000077500000000000000000000000001501761310600151365ustar00rootroot00000000000000audit-userspace-4.0.5/m4/Makefile.am000066400000000000000000000017561501761310600172030ustar00rootroot00000000000000# Makefile.am -- # Copyright 2015 Red Hat Inc., Durham, North Carolina. # All Rights Reserved. # # 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 program; see the file COPYING.lib. If not, write to # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.loT *.rej *.orig m4datadir = $(datadir)/aclocal dist_m4data_DATA = audit.m4 audit-userspace-4.0.5/m4/audit.m4000066400000000000000000000021751501761310600165130ustar00rootroot00000000000000# audit.m4 - Checks for the libaudit support # Copyright (c) 2015 Steve Grubb sgrubb@redhat.com # AC_DEFUN([AUDIT_PATH], [ AC_ARG_WITH(audit, [ --with-audit=[auto/yes/no] Add audit support [default=auto]],, with_audit=auto) # Check for libaudit API # # libaudit detection if test "x$with_audit" = xno ; then have_audit=no; else # Start by checking for header file AC_CHECK_HEADER(audit.h, audit_headers=yes, audit_headers=no) # See if we have libaudit library AC_CHECK_LIB(audit, audit_open, AUDIT_LDADD=-laudit,) # Check that results are usable if test "x$with_audit" = xyes -a "x$AUDIT_LDADD" = x ; then AC_MSG_ERROR(audit support was requested and the library was not found) fi if test "x$AUDIT_LDADD" != x -a "$audit_headers" = no ; then AC_MSG_ERROR(audit libraries found but headers are missing) fi fi AC_SUBST(AUDIT_LDADD) AC_MSG_CHECKING(whether to use audit) if test "x$AUDIT_LDADD" != x ; then AC_DEFINE(HAVE_AUDIT,1,[audit support]) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi ]) audit-userspace-4.0.5/m4/ax_prog_cc_for_build.m4000066400000000000000000000077021501761310600215370ustar00rootroot00000000000000# =========================================================================== # http://www.gnu.org/software/autoconf-archive/ax_prog_cc_for_build.html # =========================================================================== # # SYNOPSIS # # AX_PROG_CC_FOR_BUILD # # DESCRIPTION # # This macro searches for a C compiler that generates native executables, # that is a C compiler that surely is not a cross-compiler. This can be # useful if you have to generate source code at compile-time like for # example GCC does. # # The macro sets the CC_FOR_BUILD and CPP_FOR_BUILD macros to anything # needed to compile or link (CC_FOR_BUILD) and preprocess (CPP_FOR_BUILD). # The value of these variables can be overridden by the user by specifying # a compiler with an environment variable (like you do for standard CC). # # It also sets BUILD_EXEEXT and BUILD_OBJEXT to the executable and object # file extensions for the build platform, and GCC_FOR_BUILD to `yes' if # the compiler we found is GCC. All these variables but GCC_FOR_BUILD are # substituted in the Makefile. # # LICENSE # # Copyright (c) 2008 Paolo Bonzini # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. #serial 8 AU_ALIAS([AC_PROG_CC_FOR_BUILD], [AX_PROG_CC_FOR_BUILD]) AC_DEFUN([AX_PROG_CC_FOR_BUILD], [dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_CPP])dnl AC_REQUIRE([AC_EXEEXT])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl dnl Use the standard macros, but make them use other variable names dnl pushdef([ac_cv_prog_CPP], ac_cv_build_prog_CPP)dnl pushdef([ac_cv_prog_gcc], ac_cv_build_prog_gcc)dnl pushdef([ac_cv_prog_cc_works], ac_cv_build_prog_cc_works)dnl pushdef([ac_cv_prog_cc_cross], ac_cv_build_prog_cc_cross)dnl pushdef([ac_cv_prog_cc_g], ac_cv_build_prog_cc_g)dnl pushdef([ac_cv_exeext], ac_cv_build_exeext)dnl pushdef([ac_cv_objext], ac_cv_build_objext)dnl pushdef([ac_exeext], ac_build_exeext)dnl pushdef([ac_objext], ac_build_objext)dnl pushdef([CC], CC_FOR_BUILD)dnl pushdef([CPP], CPP_FOR_BUILD)dnl pushdef([CFLAGS], CFLAGS_FOR_BUILD)dnl pushdef([CPPFLAGS], CPPFLAGS_FOR_BUILD)dnl pushdef([LDFLAGS], LDFLAGS_FOR_BUILD)dnl pushdef([host], build)dnl pushdef([host_alias], build_alias)dnl pushdef([host_cpu], build_cpu)dnl pushdef([host_vendor], build_vendor)dnl pushdef([host_os], build_os)dnl pushdef([ac_cv_host], ac_cv_build)dnl pushdef([ac_cv_host_alias], ac_cv_build_alias)dnl pushdef([ac_cv_host_cpu], ac_cv_build_cpu)dnl pushdef([ac_cv_host_vendor], ac_cv_build_vendor)dnl pushdef([ac_cv_host_os], ac_cv_build_os)dnl pushdef([ac_cpp], ac_build_cpp)dnl pushdef([ac_compile], ac_build_compile)dnl pushdef([ac_link], ac_build_link)dnl save_cross_compiling=$cross_compiling save_ac_tool_prefix=$ac_tool_prefix cross_compiling=no ac_tool_prefix= AC_PROG_CC AC_PROG_CPP AC_EXEEXT ac_tool_prefix=$save_ac_tool_prefix cross_compiling=$save_cross_compiling dnl Restore the old definitions dnl popdef([ac_link])dnl popdef([ac_compile])dnl popdef([ac_cpp])dnl popdef([ac_cv_host_os])dnl popdef([ac_cv_host_vendor])dnl popdef([ac_cv_host_cpu])dnl popdef([ac_cv_host_alias])dnl popdef([ac_cv_host])dnl popdef([host_os])dnl popdef([host_vendor])dnl popdef([host_cpu])dnl popdef([host_alias])dnl popdef([host])dnl popdef([LDFLAGS])dnl popdef([CPPFLAGS])dnl popdef([CFLAGS])dnl popdef([CPP])dnl popdef([CC])dnl popdef([ac_objext])dnl popdef([ac_exeext])dnl popdef([ac_cv_objext])dnl popdef([ac_cv_exeext])dnl popdef([ac_cv_prog_cc_g])dnl popdef([ac_cv_prog_cc_cross])dnl popdef([ac_cv_prog_cc_works])dnl popdef([ac_cv_prog_gcc])dnl popdef([ac_cv_prog_CPP])dnl dnl Finally, set Makefile variables dnl BUILD_EXEEXT=$ac_build_exeext BUILD_OBJEXT=$ac_build_objext AC_SUBST(BUILD_EXEEXT)dnl AC_SUBST(BUILD_OBJEXT)dnl AC_SUBST([CFLAGS_FOR_BUILD])dnl AC_SUBST([CPPFLAGS_FOR_BUILD])dnl AC_SUBST([LDFLAGS_FOR_BUILD])dnl ]) audit-userspace-4.0.5/m4/cap-ng.m4000066400000000000000000000023261501761310600165500ustar00rootroot00000000000000# libcap-ng.m4 - Checks for the libcap-ng support # Copyright (c) 2009 Steve Grubb sgrubb@redhat.com # AC_DEFUN([LIBCAP_NG_PATH], [ AC_ARG_WITH(libcap-ng, [ --with-libcap-ng=[auto/yes/no] Add Libcap-ng support [default=auto]],, with_libcap_ng=auto) # Check for Libcap-ng API # # libcap-ng detection if test x$with_libcap_ng = xno ; then have_libcap_ng=no; else # Start by checking for header file AC_CHECK_HEADER(cap-ng.h, capng_headers=yes, capng_headers=no) # See if we have libcap-ng library AC_CHECK_LIB(cap-ng, capng_clear, CAPNG_LDADD=-lcap-ng,) # Check results are usable if test x$with_libcap_ng = xyes -a x$CAPNG_LDADD = x ; then AC_MSG_ERROR(libcap-ng support was requested and the library was not found) fi if test x$CAPNG_LDADD != x -a $capng_headers = no ; then AC_MSG_ERROR(libcap-ng libraries found but headers are missing) fi fi AC_SUBST(CAPNG_LDADD) AC_MSG_CHECKING(whether to use libcap-ng) if test x$CAPNG_LDADD != x ; then AC_DEFINE(HAVE_LIBCAP_NG,1,[libcap-ng support]) CAPNG_PKG="libcap-ng" AC_SUBST(CAPNG_PKG) AC_MSG_RESULT(yes) else AC_MSG_RESULT(no) fi ]) audit-userspace-4.0.5/original-readme.txt000066400000000000000000000115301501761310600204160ustar00rootroot00000000000000This is some background information about the Linux Auditing Framework. LICENSE ======= The audit daemon is released as GPL'd code. The audit daemon's libraries libaudit.* and libauparse.* are released under LGPL so that it may be linked with 3rd party software. BUILDING ======== See the Install(.tmp) file. USAGE ===== See the man pages for audit, auditctl, audit.rules, ausearch, and aureport. DISCUSSION ========== Original lkml thread(s): https://marc.info/?t=107815888100001&r=1&w=2 https://marc.info/?t=107901570800002&r=1&w=2 There is a linux audit mail list where any question whether kernel design, setup and configuration, or usage can be discussed: http://www.redhat.com/mailman/listinfo/linux-audit DESIGN INFO (Very old) ===================== The main goals were to provide system call auditing with 1) as low overhead as possible, and 2) without duplicating functionality that is already provided by SELinux (and/or other security infrastructures). This framework will work "stand-alone", but is not designed to provide, e.g., CAPP functionality without another security component in place. There are two main parts, one that is always on (generic logging in audit.c) and one that you can disable at boot- or run-time (per-system-call auditing in auditsc.c). The patch includes changes to security/selinux/avc.c as an example of how system-call auditing can be integrated with other code that identifies auditable events. Logging: 1) Uses a netlink socket for communication with user-space. All messages are logged via the netlink socket if a user-space daemon is listening. If not, the messages are logged via printk to the syslog daemon (by default). 2) Messages can be dropped (optionally) based on message rate or memory use (this isn't fully integrated into the selinux/avc.c part of the patch: the avc.c code that currently does this can be eliminated). 3) When some part of the kernel generates part of an audit record, the partial record is sent immediately to user-space, AND the system call "auditable" flag is automatically set for that call -- thereby producing extra information at syscall exit (if syscall auditing is enabled). System-call auditing: 1) At task-creation time, an audit context is allocated and linked off the task structure. 2) At syscall entry time, if the audit context exists, information is filled in (syscall number, timestamp; but not arguments). 3) During the system call, calls to getname() and path_lookup() are intercepted. These routines are called when the kernel is actually looking up information that will be used to make the decision about whether the syscall will succeed or fail. An effort has been made to avoid copying the information that getname generates, since getname is already making a kernel-private copy of the information. [Note that storing copies of all syscall arguments requires complexity and overhead that arguably isn't needed. With this patch, for example, if chroot("foo") fails because you are not root, "foo" will not appear in the audit record because the kernel determined the syscall cannot proceed before it ever needed to look up "foo". This approach avoids storing user-supplied information that could be misleading or unreliable (e.g., due to a cooperative shared-memory attack) in favor of reporting information actually used by the kernel.] 4) At syscall exit time, if the "auditable" flag has been set (e.g., because SELinux generated an avc record; or some other part of the kernel detected an auditable event), the syscall-part of the audit record is generated, including file names and inode numbers (if available). Some of this information is currently complementary to the information that selinux/avc.c generates (e.g., file names and some inode numbers), but some is less complete (e.g., getname doesn't return a fully-qualified path, and this patch does not add the overhead of determining one). [Note that the complete audit record comes to userspace in pieces, which eliminates the need to store messages for arbitrarily long periods inside the kernel.] 5) At task-exit time, the audit context is destroyed. At steps 1, 2, and 4, simple filtering can be done (e.g., a database role uid might have syscall auditing disabled for performance reasons). The filtering is simple and could be made more complex. However, I tried to implement as much filtering as possible without adding significant overhead (e.g., d_path()). In general, the audit framework should rely on some other kernel component (e.g., SELinux) to make the majority of the decisions about what is and is not auditable. audit-userspace-4.0.5/rules/000077500000000000000000000000001501761310600157505ustar00rootroot00000000000000audit-userspace-4.0.5/rules/10-base-config.rules000066400000000000000000000003641501761310600214220ustar00rootroot00000000000000## First rule - delete all -D ## Increase the buffers to survive stress events. ## Make this bigger for busy systems -b 8192 ## This determine how long to wait in burst of events --backlog_wait_time 60000 ## Set failure mode to syslog -f 1 audit-userspace-4.0.5/rules/10-no-audit.rules000066400000000000000000000004341501761310600207630ustar00rootroot00000000000000## This set of rules is to suppress the performance effects of the ## audit system. The result is that you only get hardwired events. -D ## This suppresses syscall auditing for all tasks started ## with this rule in effect. Remove it if you need syscall ## auditing. -a task,never audit-userspace-4.0.5/rules/11-loginuid.rules000066400000000000000000000001351501761310600210540ustar00rootroot00000000000000## Make the loginuid immutable. This prevents tampering with the auid. --loginuid-immutable audit-userspace-4.0.5/rules/12-cont-fail.rules000066400000000000000000000005151501761310600211210ustar00rootroot00000000000000## This rule will cause auditctl to continue loading rules when it runs ## across an unsupported field or a rule with a syntax error however it will ## report an error at exit. The normal action is to report the line and ## issue with the rule and exit immediately with an error to get the admin's ## attention to fix the rules. -c audit-userspace-4.0.5/rules/12-ignore-error.rules000066400000000000000000000005071501761310600216600ustar00rootroot00000000000000## This rule will cause auditctl to continue loading rules when it runs ## across an unsupported field or a rule with a syntax error but exit with ## success reason code. The normal action is to report the line and issue with ## the rule and exit immediately with an error to get the admin's attention to ## fix the rules. -i audit-userspace-4.0.5/rules/20-dont-audit.rules000066400000000000000000000010041501761310600213060ustar00rootroot00000000000000## This is for don't audit rules. We put these early because audit ### is a first match wins system. Uncomment the rules you want. ## Cron jobs fill the logs with stuff we normally don't want #-a never,user -F subj_type=crond_t ## This prevents chrony from overwhelming the logs #-a never,exit -F arch=x86_64 -S adjtimex -F auid=unset -F uid=chrony -F subj_type=chronyd_t ### This is not very interesting and wastes a lot of space if ### the server is public facing #-a always,exclude -F msgtype=CRYPTO_KEY_USER audit-userspace-4.0.5/rules/21-no32bit.rules000066400000000000000000000004211501761310600205210ustar00rootroot00000000000000## If you are on a 64 bit platform, everything _should_ be running ## in 64 bit mode. This rule will detect any use of the 32 bit syscalls ## because this might be a sign of someone exploiting a hole in the 32 ## bit ABI. -a always,exit -F arch=b32 -S all -F key=32bit-abi audit-userspace-4.0.5/rules/22-ignore-chrony.rules000066400000000000000000000003761501761310600220360ustar00rootroot00000000000000## This rule suppresses the time-change event when chrony does time updates -a never,exit -F arch=b64 -S adjtimex -F auid=unset -F uid=chrony -F subj_type=chronyd_t -a never,exit -F arch=b32 -S adjtimex -F auid=unset -F uid=chrony -F subj_type=chronyd_t audit-userspace-4.0.5/rules/23-ignore-filesystems.rules000066400000000000000000000007731501761310600231050ustar00rootroot00000000000000# This rule suppresses events that originate on the below file systems. # Typically you would use this in conjunction with rules to monitor # kernel modules. The filesystem listed are known to cause hundreds of # path records during kernel module load. As an aside, if you do see the # tracefs or debugfs module load and this is a production system, you really # should look into why its getting loaded and prevent it if possible. -a never,filesystem -F fstype=tracefs -a never,filesystem -F fstype=debugfs audit-userspace-4.0.5/rules/30-ospp-v42-1-create-failed.rules000066400000000000000000000027341501761310600234650ustar00rootroot00000000000000## Unsuccessful file creation (open with O_CREAT) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create audit-userspace-4.0.5/rules/30-ospp-v42-1-create-success.rules000066400000000000000000000013521501761310600237040ustar00rootroot00000000000000## Successful file creation (open with O_CREAT) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create -a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create audit-userspace-4.0.5/rules/30-ospp-v42-2-modify-failed.rules000066400000000000000000000031561501761310600235110ustar00rootroot00000000000000## Unsuccessful file modifications (open for write or truncate) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification audit-userspace-4.0.5/rules/30-ospp-v42-2-modify-success.rules000066400000000000000000000014721501761310600237340ustar00rootroot00000000000000## Successful file modifications (open for write or truncate) -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification -a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification audit-userspace-4.0.5/rules/30-ospp-v42-3-access-failed.rules000066400000000000000000000011611501761310600234560ustar00rootroot00000000000000## Unsuccessful file access (any other opens) This has to go last. -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access audit-userspace-4.0.5/rules/30-ospp-v42-3-access-success.rules000066400000000000000000000006171501761310600237070ustar00rootroot00000000000000## Successful file access (any other opens) This has to go last. ## These next two are likely to result in a whole lot of events -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access audit-userspace-4.0.5/rules/30-ospp-v42-4-delete-failed.rules000066400000000000000000000010621501761310600234600ustar00rootroot00000000000000## Unsuccessful file delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete audit-userspace-4.0.5/rules/30-ospp-v42-4-delete-success.rules000066400000000000000000000004341501761310600237060ustar00rootroot00000000000000## Successful file delete -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete audit-userspace-4.0.5/rules/30-ospp-v42-5-perm-change-failed.rules000066400000000000000000000014601501761310600244070ustar00rootroot00000000000000## Unsuccessful permission change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change audit-userspace-4.0.5/rules/30-ospp-v42-5-perm-change-success.rules000066400000000000000000000006361501761310600246370ustar00rootroot00000000000000## Successful permission change -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change audit-userspace-4.0.5/rules/30-ospp-v42-6-owner-change-failed.rules000066400000000000000000000011031501761310600245710ustar00rootroot00000000000000## Unsuccessful ownership change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change audit-userspace-4.0.5/rules/30-ospp-v42-6-owner-change-success.rules000066400000000000000000000004471501761310600250270ustar00rootroot00000000000000## Successful ownership change -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change audit-userspace-4.0.5/rules/30-ospp-v42.rules000066400000000000000000000221351501761310600206410ustar00rootroot00000000000000## The purpose of these rules is to meet the requirements for Operating ## System Protection Profile (OSPP)v4.2. These rules depends on having ## the following rule files copied to /etc/audit/rules.d: ## ## 10-base-config.rules, 11-loginuid.rules, ## 30-ospp-v42-1-create-failed.rules, 30-ospp-v42-1-create-success.rules, ## 30-ospp-v42-2-modify-failed.rules, 30-ospp-v42-2-modify-success.rules, ## 30-ospp-v42-3-access-failed.rules, 30-ospp-v42-3-access-success.rules, ## 30-ospp-v42-4-delete-failed.rules, 30-ospp-v42-4-delete-success.rules, ## 30-ospp-v42-5-perm-change-failed.rules, ## 30-ospp-v42-5-perm-change-success.rules, ## 30-ospp-v42-6-owner-change-failed.rules, ## 30-ospp-v42-6-owner-change-success.rules ## ## original copies may be found in /usr/share/audit-rules ## User add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch passwd and ## shadow for writes -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify ## User enable and disable. This is entirely handled by pam. ## Group add delete modify. This is covered by pam. However, someone could ## open a file and directly create or modify a user, so we'll watch group and ## gshadow for writes -a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify -a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify -a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify -a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify -a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify ## Use of special rights for config changes. This would be use of setuid ## programs that relate to user accts. This is not all setuid apps because ## requirements are only for ones that affect system configuration. -a always,exit -F arch=b32 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b32 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes -a always,exit -F arch=b64 -F path=/usr/sbin/grub2-set-bootflag -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes ## Privilege escalation via su or sudo. This is entirely handled by pam. ## Special case for systemd-run. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation ## Special case for pkexec. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation ## Watch for configuration changes to privilege escalation. -a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes -a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=special-config-changes -a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes -a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes ## Audit log access -a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail -a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail ## Attempts to Alter Process and Session Initiation Information -a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session -a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session -a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session -a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session -a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session -a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session ## Attempts to modify MAC controls -a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy -a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy ## Software updates. This is entirely handled by rpm. ## System start and shutdown. This is entirely handled by systemd ## Kernel Module loading. This is handled in 43-module-load.rules ## Application invocation. The requirements list an optional requirement ## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to ## state results from that policy. This would be handled entirely by ## that daemon. audit-userspace-4.0.5/rules/30-pci-dss-v31.rules000066400000000000000000000202741501761310600212220ustar00rootroot00000000000000## The purpose of these rules is to meet the pci-dss v3.1 auditing requirements ## These rules depends on having 10-base-config.rules & 99-finalize.rules ## installed. ## NOTE: ## 1) if this is being used on a 32 bit machine, comment out the b64 lines ## 2) These rules assume that login under the root account is not allowed. ## 3) It is also assumed that 1000 represents the first usable user account. To ## be sure, look at UID_MIN in /etc/login.defs. ## 4) If these rules generate too much spurious data for your tastes, limit the ## syscall file rules with a directory, like -F dir=/etc ## 5) You can search for the results on the key fields in the rules ## ## 10.1 Implement audit trails to link all access to individual user. ## This requirement is implicitly met ## 10.2.1 Implement audit trails to detect user accesses to cardholder data ## This would require a watch on the database that excludes the daemon's ## access. This rule is commented out due to needing a path name #-a always,exit -F arch=b32 -F path=path-to-db -F auid>=1000 -F auid!=unset -F uid!=daemon-acct -F perm=r -F key=10.2.1-cardholder-access #-a always,exit -F arch=b64 -F path=path-to-db -F auid>=1000 -F auid!=unset -F uid!=daemon-acct -F perm=r -F key=10.2.1-cardholder-access ## 10.2.2 Log administrative action. To meet this, you need to enable tty ## logging. The pam config below should be placed into su and sudo pam stacks. ## session required pam_tty_audit.so disable=* enable=root ## Special case for systemd-run. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation ## Special case for pkexec. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation ## Watch for configuration changes to privilege escalation. -a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=10.2.2-priv-config-changes -a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=10.2.2-priv-config-changes -a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=10.2.2-priv-config-changes -a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=10.2.2-priv-config-changes ## 10.2.3 Access to all audit trails. -a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=10.2.3-access-audit-trail -a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=10.2.3-access-audit-trail -a always,exit -F arch=b32 -F path=/usr/sbin/ausearch -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b64 -F path=/usr/sbin/ausearch -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b32 -F path=/usr/sbin/aureport -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b64 -F path=/usr/sbin/aureport -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b32 -F path=/usr/sbin/aulast -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b64 -F path=/usr/sbin/aulast -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b32 -F path=/usr/sbin/aulastlog -F perm=x -F key=10.2.3-access-audit-trail -a always,exit -F arch=b64 -F path=/usr/sbin/aulastlog -F perm=x -F key=10.2.3-access-audit-trail ## 10.2.4 Invalid logical access attempts. This is naturally met by pam. You ## can find these events with: ausearch --start today -m user_login -sv no -i ## 10.2.5.a Use of I&A mechanisms is logged. Pam naturally handles this. ## you can find the events with: ## ausearch --start today -m user_auth,user_chauthtok -i ## 10.2.5.b All elevation of privileges is logged -a always,exit -F arch=b64 -S setuid -F a0=0 -F exe=/usr/bin/su -F key=10.2.5.b-elevated-privs-session -a always,exit -F arch=b32 -S setuid -F a0=0 -F exe=/usr/bin/su -F key=10.2.5.b-elevated-privs-session -a always,exit -F arch=b64 -S setresuid -F a0=0 -F exe=/usr/bin/sudo -F key=10.2.5.b-elevated-privs-session -a always,exit -F arch=b32 -S setresuid -F a0=0 -F exe=/usr/bin/sudo -F key=10.2.5.b-elevated-privs-session -a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -F key=10.2.5.b-elevated-privs-setuid -a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -F key=10.2.5.b-elevated-privs-setuid ## 10.2.5.c All changes, additions, or deletions to any account are logged ## This is implicitly covered by shadow-utils. We will place some rules ## in case someone tries to hand edit the trusted databases -a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b32 -F path=/etc/security/opasswd -F perm=wa -F key=10.2.5.c-accounts -a always,exit -F arch=b64 -F path=/etc/security/opasswd -F perm=wa -F key=10.2.5.c-accounts ## 10.2.6 Verify the following are logged: ## Initialization of audit logs ## Stopping or pausing of audit logs. ## These are handled implicitly by auditd ## 10.2.7 Creation and deletion of system-level objects ## This requirement seems to be database table related and not audit ## 10.3 Record at least the following audit trail entries ## 10.3.1 through 10.3.6 are implicitly met by the audit system. ## 10.4.2b Time data is protected. ## We will place rules to check time synchronization -a always,exit -F arch=b32 -S adjtimex,settimeofday,stime -F key=10.4.2b-time-change -a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=10.4.2b-time-change -a always,exit -F arch=b32 -S clock_settime -F a0=0x0 -F key=10.4.2b-time-change -a always,exit -F arch=b64 -S clock_settime -F a0=0x0 -F key=10.4.2b-time-change # Introduced in 2.6.39, commented out because it can make false positives #-a always,exit -F arch=b32 -S clock_adjtime -F key=10.4.2b-time-change #-a always,exit -F arch=b64 -S clock_adjtime -F key=10.4.2b-time-change -a always,exit -F arch=b32 -F path=/etc/localtime -F perm=wa -F key=10.4.2b-time-change -a always,exit -F arch=b64 -F path=/etc/localtime -F perm=wa -F key=10.4.2b-time-change ## 10.5 Secure audit trails so they cannot be altered ## The audit system protects audit logs by virtue of being the root user. ## That means that no normal user can tamper with the audit trail. If for ## some reason you suspect that admins may be malicious or that their acct ## could be compromised, then enable the remote logging plugin and get the ## logs off the system to assure that there is an unaltered copy. ## 10.5.1 Limit viewing of audit trails to those with a job-related need. ## The audit daemon by default limits viewing of the audit trail to root. ## If someone that is not an admin has a job related need to see logs, then ## create a unique group for people with this need and set the log_group ## configuration item in auditd.conf ## 10.5.2 Protect audit trail files from unauthorized modifications. ## See discussion in 10.5 above ## 10.5.3 Promptly back up audit trail files to a centralized log server ## See discussion in 10.5 above ## 10.5.4 Write logs for external-facing technologies onto a secure, ## centralized, internal log serve ## See discussion in 10.5 above ## 10.5.5 Use file-integrity monitoring or change-detection software on logs -a always,exit -F arch=b32 -F dir=/var/log/audit/ -F perm=wa -F key=10.5.5-modification-audit -a always,exit -F arch=b64 -F dir=/var/log/audit/ -F perm=wa -F key=10.5.5-modification-audit ## Feel free to add watches on other critical logs # -a always,exit -F arch=b32 -F path=path-to-log -F perm=wa -F key=10.5.5-modification-log # -a always,exit -F arch=b64 -F path=path-to-log -F perm=wa -F key=10.5.5-modification-log audit-userspace-4.0.5/rules/30-stig.rules000066400000000000000000000224011501761310600202110ustar00rootroot00000000000000## The purpose of these rules is to meet the stig auditing requirements ## These rules depends on having 10-base-config.rules & 99-finalize.rules ## installed. ## NOTE: ## 1) if this is being used on a 32 bit machine, comment out the b64 lines ## 2) These rules assume that login under the root account is not allowed. ## 3) It is also assumed that 1000 represents the first usable user account. To ## be sure, look at UID_MIN in /etc/login.defs. ## 4) If these rules generate too much spurious data for your tastes, limit the ## syscall file rules with a directory, like -F dir=/etc ## 5) You can search for the results on the key fields in the rules ## ## ## (GEN002880: CAT II) The IAO will ensure the auditing software can ## record the following for each audit event: ##- Date and time of the event ##- Userid that initiated the event ##- Type of event ##- Success or failure of the event ##- For I&A events, the origin of the request (e.g., terminal ID) ##- For events that introduce an object into a user’s address space, and ## for object deletion events, the name of the object, and in MLS ## systems, the object’s security level. ## ## Things that could affect time -a always,exit -F arch=b32 -S adjtimex,settimeofday,stime -F key=time-change -a always,exit -F arch=b64 -S adjtimex,settimeofday -F key=time-change -a always,exit -F arch=b32 -S clock_settime -F a0=0x0 -F key=time-change -a always,exit -F arch=b64 -S clock_settime -F a0=0x0 -F key=time-change # Introduced in 2.6.39, commented out because it can make false positives #-a always,exit -F arch=b32 -S clock_adjtime -F key=time-change #-a always,exit -F arch=b64 -S clock_adjtime -F key=time-change -a always,exit -F arch=b32 -F path=/etc/localtime -F perm=wa -F key=time-change -a always,exit -F arch=b64 -F path=/etc/localtime -F perm=wa -F key=time-change ## Things that affect identity -a always,exit -F arch=b32 -F path=/etc/group -F perm=wa -F key=identity -a always,exit -F arch=b64 -F path=/etc/group -F perm=wa -F key=identity -a always,exit -F arch=b32 -F path=/etc/passwd -F perm=wa -F key=identity -a always,exit -F arch=b64 -F path=/etc/passwd -F perm=wa -F key=identity -a always,exit -F arch=b32 -F path=/etc/gshadow -F perm=wa -F key=identity -a always,exit -F arch=b64 -F path=/etc/gshadow -F perm=wa -F key=identity -a always,exit -F arch=b32 -F path=/etc/shadow -F perm=wa -F key=identity -a always,exit -F arch=b64 -F path=/etc/shadow -F perm=wa -F key=identity -a always,exit -F arch=b32 -F path=/etc/security/opasswd -F perm=wa -F key=identity -a always,exit -F arch=b64 -F path=/etc/security/opasswd -F perm=wa -F key=identity ## Things that could affect system locale -a always,exit -F arch=b32 -S sethostname,setdomainname -F key=system-locale -a always,exit -F arch=b64 -S sethostname,setdomainname -F key=system-locale -a always,exit -F arch=b32 -F path=/etc/issue -F perm=wa -F key=system-locale -a always,exit -F arch=b64 -F path=/etc/issue -F perm=wa -F key=system-locale -a always,exit -F arch=b32 -F path=/etc/issue.net -F perm=wa -F key=system-locale -a always,exit -F arch=b64 -F path=/etc/issue.net -F perm=wa -F key=system-locale -a always,exit -F arch=b32 -F path=/etc/hosts -F perm=wa -F key=system-locale -a always,exit -F arch=b64 -F path=/etc/hosts -F perm=wa -F key=system-locale -a always,exit -F arch=b32 -F path=/etc/hostname -F perm=wa -F key=system-locale -a always,exit -F arch=b64 -F path=/etc/hostname -F perm=wa -F key=system-locale -a always,exit -F arch=b32 -F dir=/etc/NetworkManager/ -F perm=wa -F key=system-locale -a always,exit -F arch=b64 -F dir=/etc/NetworkManager/ -F perm=wa -F key=system-locale ## Things that could affect MAC policy -a always,exit -F arch=b32 -F dir=/etc/selinux/ -F perm=wa -F key=MAC-policy -a always,exit -F arch=b64 -F dir=/etc/selinux/ -F perm=wa -F key=MAC-policy ## (GEN002900: CAT III) The IAO will ensure audit files are retained at ## least one year; systems containing SAMI will be retained for five years. ## ## Site action - no action in config files ## (GEN002920: CAT III) The IAO will ensure audit files are backed up ## no less than weekly onto a different system than the system being ## audited or backup media. ## ## Can be done with cron script ## (GEN002700: CAT I) (Previously – G095) The SA will ensure audit data ## files have permissions of 640, or more restrictive. ## ## Done automatically by auditd ## (GEN002720-GEN002840: CAT II) (Previously – G100-G106) The SA will ## configure the auditing system to audit the following events for all ## users and root: ## ## - Logon (unsuccessful and successful) and logout (successful) ## ## Handled by pam, sshd, login, and gdm ## Might also want to watch these files if needing extra information #-a always,exit -F arch=b32 -F path=/var/log/tallylog -F perm=wa -F key=logins #-a always,exit -F arch=b64 -F path=/var/log/tallylog -F perm=wa -F key=logins #-a always,exit -F arch=b32 -F path=/var/run/faillock -F perm=wa -F key=logins #-a always,exit -F arch=b64 -F path=/var/run/faillock -F perm=wa -F key=logins #-a always,exit -F arch=b32 -F path=/var/log/lastlog -F perm=wa -F key=logins #-a always,exit -F arch=b64 -F path=/var/log/lastlog -F perm=wa -F key=logins ##- Process and session initiation (unsuccessful and successful) ## ## The session initiation is audited by pam without any rules needed. ## Might also want to watch this file if needing extra information #-a always,exit -F arch=b32 -F path=/var/run/utmp -F perm=wa -F key=session #-a always,exit -F arch=b64 -F path=/var/run/utmp -F perm=wa -F key=session #-a always,exit -F arch=b32 -F path=/var/log/btmp -F perm=wa -F key=session #-a always,exit -F arch=b64 -F path=/var/log/btmp -F perm=wa -F key=session #-a always,exit -F arch=b32 -F path=/var/log/wtmp -F perm=wa -F key=session #-a always,exit -F arch=b64 -F path=/var/log/wtmp -F perm=wa -F key=session ##- Discretionary access control permission modification (unsuccessful ## and successful use of chown/chmod) -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod ##- Unauthorized access attempts to files (unsuccessful) -a always,exit -F arch=b32 -S open,creat,truncate,ftruncate,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access -a always,exit -F arch=b32 -S open,creat,truncate,ftruncate,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access -a always,exit -F arch=b64 -S open,truncate,ftruncate,creat,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access -a always,exit -F arch=b64 -S open,truncate,ftruncate,creat,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access ##- Use of print command (unsuccessful and successful) ##- Export to media (successful) ## You have to mount media before using it. You must disable all automounting ## so that its done manually in order to get the correct user requesting the ## export -a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=unset -F key=export -a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=unset -F key=export ##- System startup and shutdown (unsuccessful and successful) ##- Files and programs deleted by the user (successful and unsuccessful) -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=unset -F key=delete ##- All system administration actions ##- All security personnel actions ## ## Look for pam_tty_audit and add it to your login entry point's pam configs. ## If that is not found, use sudo which should be patched to record its ## commands to the audit system. Do not allow unrestricted root shells or ## sudo cannot record the action. -a always,exit -F arch=b32 -F path=/etc/sudoers -F perm=wa -F key=actions -a always,exit -F arch=b64 -F path=/etc/sudoers -F perm=wa -F key=actions -a always,exit -F arch=b32 -F dir=/etc/sudoers.d/ -F perm=wa -F key=actions -a always,exit -F arch=b64 -F dir=/etc/sudoers.d/ -F perm=wa -F key=actions ## Special case for systemd-run. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/systemd-run -F perm=x -F auid!=unset -F key=maybe-escalation ## Special case for pkexec. It is not audit aware, specifically watch it -a always,exit -F arch=b32 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation -a always,exit -F arch=b64 -F path=/usr/bin/pkexec -F perm=x -F key=maybe-escalation ## (GEN002860: CAT II) (Previously – G674) The SA and/or IAO will ##ensure old audit logs are closed and new audit logs are started daily. ## ## Site action. Can be assisted by a cron job audit-userspace-4.0.5/rules/31-privileged.rules000066400000000000000000000030771501761310600214060ustar00rootroot00000000000000##- Use of privileged commands (unsuccessful and successful) ## You can run the following commands to generate the rules (don't forget to ## add arch=b32 rules, too): #find /bin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' > priv.rules #find /sbin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules #find /usr/bin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules #find /usr/sbin -type f -perm -04000 2>/dev/null | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $1 }' >> priv.rules #filecap /bin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F arch=b64 -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules #filecap /sbin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F path=%s -F arch=b64 -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules #filecap /usr/bin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules #filecap /usr/sbin 2>/dev/null | sed '1d' | awk '{ printf "-a always,exit -F arch=b64 -F path=%s -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged\n", $2 }' >> priv.rules audit-userspace-4.0.5/rules/32-power-abuse.rules000066400000000000000000000003251501761310600214770ustar00rootroot00000000000000## The purpose of this rule is to detect when an admin may be abusing power ## by looking in user's home dir. -a always,exit -F dir=/home -F uid=0 -F auid>=1000 -F auid!=unset -C auid!=obj_uid -F key=power-abuse audit-userspace-4.0.5/rules/40-local.rules000066400000000000000000000002641501761310600203410ustar00rootroot00000000000000## Put your own watches after this point # -a exit,always -F arch=b64 -F path=file -F perm=rwxa -F key=text # -a exit,always -F arch=b64 -F dir=directory -F perm=rwxa -F key=text audit-userspace-4.0.5/rules/41-containers.rules000066400000000000000000000006671501761310600214240ustar00rootroot00000000000000## Use these rules if you want to log container events ## watch for container creation -a always,exit -F arch=b32 -S clone -F a0&0x7C020000 -F key=container-create -a always,exit -F arch=b64 -S clone -F a0&0x7C020000 -F key=container-create ## watch for containers that may change their configuration -a always,exit -F arch=b32 -S unshare,setns -F key=container-config -a always,exit -F arch=b64 -S unshare,setns -F key=container-config audit-userspace-4.0.5/rules/42-injection.rules000066400000000000000000000012401501761310600212260ustar00rootroot00000000000000## These rules watch for code injection by the ptrace facility. ## This could indicate someone trying to do something bad or ## just debugging #-a always,exit -F arch=b32 -S ptrace -F key=tracing -a always,exit -F arch=b64 -S ptrace -F key=tracing -a always,exit -F arch=b32 -S ptrace -F a0=0x4 -F key=code-injection -a always,exit -F arch=b64 -S ptrace -F a0=0x4 -F key=code-injection -a always,exit -F arch=b32 -S ptrace -F a0=0x5 -F key=data-injection -a always,exit -F arch=b64 -S ptrace -F a0=0x5 -F key=data-injection -a always,exit -F arch=b32 -S ptrace -F a0=0x6 -F key=register-injection -a always,exit -F arch=b64 -S ptrace -F a0=0x6 -F key=register-injection audit-userspace-4.0.5/rules/43-module-load.rules000066400000000000000000000006161501761310600214550ustar00rootroot00000000000000## These rules watch for kernel module insertion. By monitoring ## the syscall, we do not need any watches on programs. -a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load -a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load -a always,exit -F arch=b32 -S delete_module -F key=module-unload -a always,exit -F arch=b64 -S delete_module -F key=module-unload audit-userspace-4.0.5/rules/44-installers.rules000066400000000000000000000023601501761310600214320ustar00rootroot00000000000000# These rules watch for invocation of things known to install software -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/dnf-3 -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/dnf-3 -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/yum -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/yum -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/pip -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/pip -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/npm -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/npm -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/cpan -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/cpan -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/gem -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/gem -F key=software-installer -a always,exit -F arch=b32 -F perm=x -F path=/usr/bin/luarocks -F key=software-installer -a always,exit -F arch=b64 -F perm=x -F path=/usr/bin/luarocks -F key=software-installer audit-userspace-4.0.5/rules/70-einval.rules000066400000000000000000000005061501761310600205270ustar00rootroot00000000000000## These are rules are to locate poorly written programs. ## Its never planned to waste time on a syscall with incorrect parameters ## This is more of a debugging step than something people should run with ## in production. -a never,exit -F arch=b64 -S rt_sigreturn -a always,exit -S all -F exit=-EINVAL -F key=einval-retcode audit-userspace-4.0.5/rules/71-networking.rules000066400000000000000000000002271501761310600214410ustar00rootroot00000000000000## This is to check if the system is making or receiving connections ## externally -a always,exit -F arch=b64 -S accept,connect -F key=external-access audit-userspace-4.0.5/rules/99-finalize.rules000066400000000000000000000001261501761310600210630ustar00rootroot00000000000000## Make the configuration immutable - reboot is required to change audit rules #-e 2 audit-userspace-4.0.5/rules/Makefile.am000066400000000000000000000035351501761310600200120ustar00rootroot00000000000000# Makefile.am -- # Copyright 2016-19 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig EXTRA_DIST = 10-base-config.rules 10-no-audit.rules 11-loginuid.rules \ 12-ignore-error.rules 12-cont-fail.rules \ 20-dont-audit.rules 21-no32bit.rules 22-ignore-chrony.rules \ 23-ignore-filesystems.rules \ 30-stig.rules 30-pci-dss-v31.rules 30-ospp-v42.rules \ 30-ospp-v42-1-create-failed.rules 30-ospp-v42-1-create-success.rules \ 30-ospp-v42-2-modify-failed.rules 30-ospp-v42-2-modify-success.rules \ 30-ospp-v42-3-access-failed.rules 30-ospp-v42-3-access-success.rules \ 30-ospp-v42-4-delete-failed.rules 30-ospp-v42-4-delete-success.rules \ 30-ospp-v42-5-perm-change-failed.rules \ 30-ospp-v42-5-perm-change-success.rules \ 30-ospp-v42-6-owner-change-failed.rules \ 30-ospp-v42-6-owner-change-success.rules \ 31-privileged.rules 32-power-abuse.rules \ 40-local.rules 41-containers.rules 42-injection.rules 43-module-load.rules \ 44-installers.rules \ 70-einval.rules 71-networking.rules \ 99-finalize.rules README-rules rulesdir = $(datadir)/audit-rules dist_rules_DATA = $(EXTRA_DIST) audit-userspace-4.0.5/rules/README-rules000066400000000000000000000026151501761310600177640ustar00rootroot00000000000000This group of rules are meant to be used with the augenrules program. The augenrules program expects rules to be located in /etc/audit/rules.d/ The rules will get processed in a specific order based on their natural sort order. To make things easier to use, the files in this directory are organized into groups with the following meanings: 10 - Kernel and auditctl configuration 20 - Rules that could match general rules but we want a different match 30 - Main rules 40 - Optional rules 50 - Server Specific rules 70 - System local rules 90 - Finalize (immutable) There is one set of rules, 31-privileged.rules, that should be regenerated. There is a script in the comments of that file. You can uncomment the commands and run the script and then rename the resulting file. The rules are not meant to be used all at once. They are pieces of a policy that should be thought out and individual files copied to /etc/audit/rules.d/ For example, if you wanted to set a system up in the STIG configuration, copy rules 10-base-config, 30-stig, 31-privileged, and 99-finalize. You can add more if you like. Also, not all arches have the same syscalls. It is expected that the rules be fine tuned for the arch they are deployed on. For example, aarch64 does not have the open syscall. It should just be deleted from the rules. Once you have the rules in the rules.d directory, you can load them by running augenrules --load audit-userspace-4.0.5/src/000077500000000000000000000000001501761310600154055ustar00rootroot00000000000000audit-userspace-4.0.5/src/Makefile.am000066400000000000000000000062551501761310600174510ustar00rootroot00000000000000# Makefile.am-- # Copyright 2004-2006, 2008,2011-16,2018 Red Hat Inc. # All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor # Boston, MA 02110-1335, USA. # # Authors: # Steve Grubb # CONFIG_CLEAN_FILES = *.rej *.orig SUBDIRS = test AM_CPPFLAGS = -I${top_srcdir} -I${top_srcdir}/lib -I${top_srcdir}/src/libev -I${top_srcdir}/auparse -I${top_srcdir}/audisp -I${top_srcdir}/common sbin_PROGRAMS = auditd auditctl aureport ausearch AM_CFLAGS = -D_GNU_SOURCE -Wno-pointer-sign ${WFLAGS} noinst_HEADERS = auditd-config.h auditd-event.h auditd-listen.h ausearch-llist.h ausearch-options.h auditctl-llist.h aureport-options.h ausearch-parse.h aureport-scan.h ausearch-lookup.h ausearch-int.h auditd-dispatch.h ausearch-string.h ausearch-nvpair.h ausearch-common.h ausearch-avc.h ausearch-time.h ausearch-lol.h auditctl-listing.h ausearch-checkpt.h auditd_SOURCES = auditd.c auditd-event.c auditd-config.c auditd-reconfig.c auditd-sendmail.c auditd-dispatch.c if ENABLE_LISTENER auditd_SOURCES += auditd-listen.c endif auditd_CFLAGS = -fPIE -DPIE -g -D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -pthread -Wno-pointer-sign ${WFLAGS} auditd_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now auditd_DEPENDENCIES = libev/libev.a auditd_LDADD = @LIBWRAP_LIBS@ ${top_builddir}/src/libev/libev.la ${top_builddir}/audisp/libdisp.la ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la -lpthread -lm $(gss_libs) ${top_builddir}/common/libaucommon.la auditctl_SOURCES = auditctl.c auditctl-llist.c delete_all.c auditctl-listing.c auditctl_CFLAGS = -fPIE -DPIE -g -D_GNU_SOURCE ${WFLAGS} auditctl_LDFLAGS = -pie -Wl,-z,relro -Wl,-z,now auditctl_LDADD = ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la ${top_builddir}/common/libaucommon.la aureport_SOURCES = aureport.c auditd-config.c ausearch-llist.c aureport-options.c ausearch-string.c ausearch-parse.c aureport-scan.c aureport-output.c ausearch-lookup.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-avc.c ausearch-lol.c aureport_LDADD = ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la ${top_builddir}/common/libaucommon.la ausearch_SOURCES = ausearch.c auditd-config.c ausearch-llist.c ausearch-options.c ausearch-report.c ausearch-match.c ausearch-string.c ausearch-parse.c ausearch-int.c ausearch-time.c ausearch-nvpair.c ausearch-lookup.c ausearch-avc.c ausearch-lol.c ausearch-checkpt.c ausearch_LDADD = ${top_builddir}/lib/libaudit.la ${top_builddir}/auparse/libauparse.la ${top_builddir}/common/libaucommon.la libev/libev.a: make -C libev audit-userspace-4.0.5/src/auditctl-listing.c000066400000000000000000000405321501761310600210350ustar00rootroot00000000000000/* auditctl-listing.c -- * Copyright 2014,16,2021-2 Red Hat Inc. * All Rights Reserved. * * 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 program; if not, write to the Free Software * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #ifdef WITH_IO_URING #include #endif #include "auditctl-listing.h" #include "private.h" #include "auditctl-llist.h" #include "auparse-idata.h" #ifndef IORING_OP_LAST #define IORING_OP_LAST 37 #endif /* Global vars */ static llist l; static int printed; extern int list_requested, interpret; extern char key[AUDIT_MAX_KEY_LEN+1]; extern const char key_sep[2]; /* * Returns 1 if rule should be printed & 0 if not */ int key_match(const struct audit_rule_data *r) { unsigned int i; size_t boffset = 0; if (key[0] == 0) return 1; // At this point, we have a key for (i = 0; i < r->field_count; i++) { int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_FILTERKEY) { char *keyptr; if (asprintf(&keyptr, "%.*s", r->values[i], &r->buf[boffset]) < 0) keyptr = NULL; else if (strstr(keyptr, key)) { free(keyptr); return 1; } free(keyptr); } if (((field >= AUDIT_SUBJ_USER && field <= AUDIT_OBJ_LEV_HIGH) && field != AUDIT_PPID) || field == AUDIT_WATCH || field == AUDIT_DIR || field == AUDIT_FILTERKEY || field == AUDIT_EXE) { boffset += r->values[i]; } } return 0; } /* * This function detects if we have a watch. A watch is detected when we * have syscall == all and a perm field. */ static int is_watch(const struct audit_rule_data *r) { unsigned int i, perm = 0, all = 1; for (i = 0; i < r->field_count; i++) { int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_PERM) perm = 1; // Watches can have only 4 field types if (field != AUDIT_PERM && field != AUDIT_FILTERKEY && field != AUDIT_DIR && field != AUDIT_WATCH) return 0; } if (((r->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_USER) && ((r->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK) && ((r->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_EXCLUDE) && ((r->flags & AUDIT_FILTER_MASK) != AUDIT_FILTER_FS)) { for (i = 0; i < (AUDIT_BITMASK_SIZE-1); i++) { if (r->mask[i] != (uint32_t)~0) { all = 0; break; } } } if (perm && all) return 1; return 0; } static int print_arch(unsigned int value, int op) { int machine; _audit_elf = value; machine = audit_elf_to_machine(_audit_elf); if (machine < 0) printf(" -F arch%s0x%X", audit_operator_to_symbol(op), (unsigned)value); else { if (interpret == 0) { if (__AUDIT_ARCH_64BIT & _audit_elf) printf(" -F arch%sb64", audit_operator_to_symbol(op)); else printf(" -F arch%sb32", audit_operator_to_symbol(op)); } else { const char *ptr = audit_machine_to_name(machine); printf(" -F arch%s%s", audit_operator_to_symbol(op), ptr); } } return machine; } static int print_syscall(const struct audit_rule_data *r, unsigned int *sc) { int count = 0; int all = 1; unsigned int i, len; int machine = audit_detect_machine(); /* Rules on the following filters do not take a syscall */ if (((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_USER) || ((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_TASK) || ((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_EXCLUDE) || ((r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_FS)) return 0; int io_uring=(r->flags & AUDIT_FILTER_MASK) == AUDIT_FILTER_URING_EXIT; if (io_uring) len = IORING_OP_LAST; else len = AUDIT_BITMASK_SIZE-1; /* See if its all or specific syscalls */ for (i = 0; i < len; i++) { if (r->mask[i] != (uint32_t)~0) { all = 0; break; } } if (all) { printf(" -S all"); count = i; } else if (io_uring) { for (i = 0; i < IORING_OP_LAST; i++) { int word = AUDIT_WORD(i); int bit = AUDIT_BIT(i); if (r->mask[word] & bit) { const char *ptr = audit_uringop_to_name(i); if (!count) printf(" -S "); if (ptr) printf("%s%s", !count ? "" : ",", ptr); else printf("%s%u", !count ? "" : ",", i); count++; *sc = i; } } } else { for (i = 0; i < AUDIT_BITMASK_SIZE * 32; i++) { int word = AUDIT_WORD(i); int bit = AUDIT_BIT(i); if (r->mask[word] & bit) { const char *ptr; if (_audit_elf) machine = audit_elf_to_machine(_audit_elf); if (machine < 0) ptr = NULL; else ptr = audit_syscall_to_name(i, machine); if (!count) printf(" -S "); if (ptr) printf("%s%s", !count ? "" : ",", ptr); else printf("%s%u", !count ? "" : ",", i); count++; *sc = i; } } } return count; } static void print_field_cmp(int value, int op) { switch (value) { case AUDIT_COMPARE_UID_TO_OBJ_UID: printf(" -C uid%sobj_uid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_OBJ_GID: printf(" -C gid%sobj_gid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_OBJ_UID: printf(" -C euid%sobj_uid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_OBJ_GID: printf(" -C egid%sobj_gid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_OBJ_UID: printf(" -C auid%sobj_uid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SUID_TO_OBJ_UID: printf(" -C suid%sobj_uid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SGID_TO_OBJ_GID: printf(" -C sgid%sobj_gid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_FSUID_TO_OBJ_UID: printf(" -C fsuid%sobj_uid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_FSGID_TO_OBJ_GID: printf(" -C fsgid%sobj_gid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_AUID: printf(" -C uid%sauid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_EUID: printf(" -C uid%seuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_FSUID: printf(" -C uid%sfsuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_UID_TO_SUID: printf(" -C uid%ssuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_FSUID: printf(" -C auid%sfsuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_SUID: printf(" -C auid%ssuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_AUID_TO_EUID: printf(" -C auid%seuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_SUID: printf(" -C euid%ssuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EUID_TO_FSUID: printf(" -C euid%sfsuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SUID_TO_FSUID: printf(" -C suid%sfsuid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_EGID: printf(" -C gid%segid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_FSGID: printf(" -C gid%sfsgid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_GID_TO_SGID: printf(" -C gid%ssgid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_FSGID: printf(" -C egid%sfsgid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_EGID_TO_SGID: printf(" -C egid%ssgid", audit_operator_to_symbol(op)); break; case AUDIT_COMPARE_SGID_TO_FSGID: printf(" -C sgid%sfsgid", audit_operator_to_symbol(op)); break; } } /* * This function prints 1 rule from the kernel reply */ static void print_rule(const struct audit_rule_data *r) { unsigned int i, count = 0, sc = 0; size_t boffset = 0; int mach = -1, watch = is_watch(r); unsigned long long a0 = 0, a1 = 0; if (!watch) { /* This is syscall auditing */ printf("-a %s,%s", audit_action_to_name((int)r->action), audit_flag_to_name(r->flags)); // Now find the arch and print it for (i = 0; i < r->field_count; i++) { int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_ARCH) { int op = r->fieldflags[i] & AUDIT_OPERATORS; mach = print_arch(r->values[i], op); } } // And last do the syscalls count = print_syscall(r, &sc); } // Now iterate over the fields for (i = 0; i < r->field_count; i++) { const char *name; int op = r->fieldflags[i] & AUDIT_OPERATORS; int field = r->fields[i] & ~AUDIT_OPERATORS; if (field == AUDIT_ARCH) continue; // already printed name = audit_field_to_name(field); if (name) { // Special cases to print the different field types // in a meaningful way. if (field == AUDIT_MSGTYPE) { if (!audit_msg_type_to_name(r->values[i])) printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); else printf(" -F %s%s%s", name, audit_operator_to_symbol(op), audit_msg_type_to_name( r->values[i])); } else if ((field >= AUDIT_SUBJ_USER && field <= AUDIT_OBJ_LEV_HIGH) && field != AUDIT_PPID) { printf(" -F %s%s%.*s", name, audit_operator_to_symbol(op), r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_WATCH) { if (watch) printf("-w %.*s", r->values[i], &r->buf[boffset]); else printf(" -F path%s%.*s", audit_operator_to_symbol(op), r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_DIR) { if (watch) printf("-w %.*s", r->values[i], &r->buf[boffset]); else printf(" -F dir%s%.*s", audit_operator_to_symbol(op), r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_EXE) { printf(" -F exe%s%.*s", audit_operator_to_symbol(op), r->values[i], &r->buf[boffset]); boffset += r->values[i]; } else if (field == AUDIT_FILTERKEY) { char *rkey, *ptr, *saved; if (asprintf(&rkey, "%.*s", r->values[i], &r->buf[boffset]) < 0) rkey = NULL; boffset += r->values[i]; ptr = strtok_r(rkey, key_sep, &saved); while (ptr) { if (watch) printf(" -k %s", ptr); else printf(" -F key=%s", ptr); ptr = strtok_r(NULL, key_sep, &saved); } free(rkey); } else if (field == AUDIT_PERM) { char perms[5]; unsigned int val=r->values[i]; perms[0] = 0; if (val & AUDIT_PERM_READ) strcat(perms, "r"); if (val & AUDIT_PERM_WRITE) strcat(perms, "w"); if (val & AUDIT_PERM_EXEC) strcat(perms, "x"); if (val & AUDIT_PERM_ATTR) strcat(perms, "a"); if (watch) printf(" -p %s", perms); else printf(" -F perm=%s", perms); } else if (field == AUDIT_INODE) { // This is unsigned printf(" -F %s%s%u", name, audit_operator_to_symbol(op), r->values[i]); } else if (field == AUDIT_FIELD_COMPARE) { print_field_cmp(r->values[i], op); } else if (field >= AUDIT_ARG0 && field <= AUDIT_ARG3){ if (field == AUDIT_ARG0) a0 = r->values[i]; else if (field == AUDIT_ARG1) a1 = r->values[i]; // Show these as hex if (count > 1 || interpret == 0) printf(" -F %s%s0x%X", name, audit_operator_to_symbol(op), r->values[i]); else { // Use ignore to mean interpret const char *out; idata id; char val[32]; int type; id.syscall = sc; id.machine = mach; id.a0 = a0; id.a1 = a1; id.name = name; id.cwd = NULL; snprintf(val, 32, "%x", r->values[i]); id.val = val; type = auparse_interp_adjust_type( AUDIT_SYSCALL, name, val); out = auparse_do_interpretation(type, &id, AUPARSE_ESC_TTY); printf(" -F %s%s%s", name, audit_operator_to_symbol(op), out); free((void *)out); } } else if (field == AUDIT_EXIT) { int e = abs((int)r->values[i]); const char *err = audit_errno_to_name(e); if (((int)r->values[i] < 0) && err) printf(" -F %s%s-%s", name, audit_operator_to_symbol(op), err); else printf(" -F %s%s%d", name, audit_operator_to_symbol(op), (int)r->values[i]); } else if (field == AUDIT_FSTYPE) { if (!audit_fstype_to_name(r->values[i])) printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); else printf(" -F %s%s%s", name, audit_operator_to_symbol(op), audit_fstype_to_name( r->values[i])); } else if (field == AUDIT_LOGINUID || field == AUDIT_SESSIONID) { if (r->values[i] == -1 && interpret) printf(" -F %s%sunset", name, audit_operator_to_symbol(op)); else printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); } else { // The default is signed decimal printf(" -F %s%s%d", name, audit_operator_to_symbol(op), r->values[i]); } } else { // The field name is unknown printf(" f%d%s%d", r->fields[i], audit_operator_to_symbol(op), r->values[i]); } } printf("\n"); } void audit_print_init(void) { printed = 0; list_create(&l); } static const char *get_enable(unsigned e) { switch (e) { case 0: return "disable"; case 1: return "enabled"; case 2: return "enabled+immutable"; default: return "unknown"; } } static const char *get_failure(unsigned f) { switch (f) { case 0: return "silent"; case 1: return "printk"; case 2: return "panic"; default: return "unknown"; } } /* * This function interprets the reply and prints it to stdout. It returns * 0 if no more should be read and 1 to indicate that more messages of this * type may need to be read. */ int audit_print_reply(const struct audit_reply *rep, int fd) { _audit_elf = 0; switch (rep->type) { case NLMSG_NOOP: return 1; case NLMSG_DONE: // Close the socket so kernel can do other things audit_close(fd); if (printed == 0) printf("No rules\n"); else { lnode *n; list_first(&l); n = l.cur; while (n) { print_rule(n->r); n = list_next(&l); } list_clear(&l); } break; case NLMSG_ERROR: printf("NLMSG_ERROR %d (%s)\n", -rep->error->error, strerror(-rep->error->error)); printed = 1; break; case AUDIT_GET: if (interpret) printf("enabled %s\nfailure %s\n", get_enable(rep->status->enabled), get_failure(rep->status->failure)); else printf("enabled %u\nfailure %u\n", rep->status->enabled, rep->status->failure); printf("pid %u\nrate_limit %u\nbacklog_limit %u\n" "lost %u\nbacklog %u\n", rep->status->pid, rep->status->rate_limit, rep->status->backlog_limit, rep->status->lost, rep->status->backlog); #if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME == 1 || \ HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME == 1 printf("backlog_wait_time %u\n", rep->status->backlog_wait_time); #endif #if HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL == 1 // A newer userspace may have been compiled on new headers // and run on an older kernel. if (rep->len == NLMSG_LENGTH(sizeof(struct audit_status))) { printf("backlog_wait_time_actual %u\n", rep->status->backlog_wait_time_actual); } #endif printed = 1; break; #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 case AUDIT_GET_FEATURE: { uint32_t mask = AUDIT_FEATURE_TO_MASK( AUDIT_FEATURE_LOGINUID_IMMUTABLE); if (rep->features->mask & mask) printf("loginuid_immutable %u %s\n", !!(rep->features->features & mask), rep->features->lock & mask ? "locked" : "unlocked"); } printed = 1; break; #endif case AUDIT_LIST_RULES: list_requested = 0; if (key_match(rep->ruledata)) list_append(&l, rep->ruledata, sizeof(struct audit_rule_data) + rep->ruledata->buflen); printed = 1; return 1; default: printf("Unknown: type=%d, len=%d\n", rep->type, rep->nlh->nlmsg_len); printed = 1; break; } return 0; } audit-userspace-4.0.5/src/auditctl-listing.h000066400000000000000000000021631501761310600210400ustar00rootroot00000000000000/* * auditctl-listing.h - Header file for ausearch-llist.c * Copyright (c) 2014 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef CTLLISTING_HEADER #define CTLLISTING_HEADER #include "config.h" #include "libaudit.h" void audit_print_init(void); int audit_print_reply(const struct audit_reply *rep, int fd); int key_match(const struct audit_rule_data *r); #endif audit-userspace-4.0.5/src/auditctl-llist.c000066400000000000000000000041701501761310600205110ustar00rootroot00000000000000/* * ausearch-llist.c - Minimal linked list library * Copyright (c) 2005 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include #include #include "auditctl-llist.h" void list_create(llist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; } void list_first(llist *l) { l->cur = l->head; } void list_last(llist *l) { register lnode* node; if (l->head == NULL) return; node = l->head; while (node->next) node = node->next; l->cur = node; } lnode *list_next(llist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } int list_append(llist *l, const struct audit_rule_data *r, size_t sz) { lnode* newnode; newnode = malloc(sizeof(lnode)); if (newnode == NULL) return 1; if (r) { void *rr = malloc(sz); if (rr == NULL) { free(newnode); return 1; } memcpy(rr, r, sz); newnode->r = rr; } else newnode->r = NULL; newnode->size = sz; newnode->next = 0; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } void list_clear(llist* l) { lnode* nextnode; register lnode* current; current = l->head; while (current) { nextnode=current->next; free(current->r); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } audit-userspace-4.0.5/src/auditctl-llist.h000066400000000000000000000034431501761310600205200ustar00rootroot00000000000000/* * auditctl-llist.h - Header file for ausearch-llist.c * Copyright (c) 2005 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef CTLLIST_HEADER #define CTLLIST_HEADER #include "config.h" #include #include "libaudit.h" /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _lnode{ struct audit_rule_data *r; // The rule from the kernel size_t size; // Size of the rule struct struct _lnode *next; // Next node pointer } lnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { lnode *head; // List head lnode *cur; // Pointer to current node unsigned int cnt; // How many items in this list } llist; void list_create(llist *l); void list_first(llist *l); void list_last(llist *l); lnode *list_next(llist *l); static inline lnode *list_get_cur(const llist *l) { return l->cur; } int list_append(llist *l, const struct audit_rule_data *r, size_t sz); void list_clear(llist* l); #endif audit-userspace-4.0.5/src/auditctl.c000066400000000000000000001326451501761310600173750ustar00rootroot00000000000000/* auditctl.c -- * Copyright 2004-2017,20-23 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith * Richard Guy Briggs */ #include "config.h" #include #include #include #include /* strdup needs xopen define */ #include #include #include #include #include #include #include #include #include #include #include /* For basename */ #include /* PATH_MAX */ #include #include // SYS_pidfd_open #include #include "libaudit.h" #include "auditctl-listing.h" #include "private.h" #include "common.h" /* This define controls the size of the line that we will request when * reading in rules from a file. */ #define LINE_SIZE 6144 #define NUM_HANDLERS (sizeof(opt_handlers) / sizeof(opt_handlers[0])) enum { OPT_DEPRECATED = -3, OPT_SUCCESS_NO_REPLY = -2, OPT_ERROR_NO_REPLY = -1, OPT_SUCCESS_REPLY = 0, OPT_SUCCESS_RULE = 1 }; /* Global functions */ static int handle_request(int status); static void get_reply(void); extern int delete_all_rules(int fd); /* Global vars */ int list_requested = 0, interpret = 0; char key[AUDIT_MAX_KEY_LEN+1]; const char key_sep[2] = { AUDIT_KEY_SEPARATOR, 0 }; static unsigned int keylen; static int fd = -1; static int add = AUDIT_FILTER_UNSET, del = AUDIT_FILTER_UNSET, action = -1; static int ignore = 0, continue_error = 0; static int exclude = 0; static int multiple = 0; static struct audit_rule_data *rule_new = NULL; /* * This function will reset everything used for each loop when loading * a ruleset from a file. */ static int reset_vars(void) { list_requested = 0; _audit_syscalladded = 0; _audit_permadded = 0; _audit_archadded = 0; _audit_exeadded = 0; _audit_filterfsadded = 0; _audit_elf = 0; add = AUDIT_FILTER_UNSET; del = AUDIT_FILTER_UNSET; action = -1; exclude = 0; multiple = 0; audit_rule_free_data(rule_new); rule_new = audit_rule_create_data(); if (fd < 0) { if ((fd = audit_open()) < 0) { audit_msg(LOG_ERR, "Cannot open netlink audit socket"); return 1; } } return 0; } static void usage(void) { printf( "usage: auditctl [options]\n" " -a Append rule to end of ist with ction\n" " -A Add rule at beginning of ist with ction\n" " -b Set max number of outstanding audit buffers\n" " allowed Default=64\n" " -c Continue through errors in rules\n" " -C f=f Compare collected fields if available:\n" " Field name, operator(=,!=), field name\n" " -d Delete rule from ist with ction\n" " l=task,exit,user,exclude,filesystem\n" " a=never,always\n" " -D Delete all rules and watches\n" " -e [0..2] Set enabled flag\n" " -f [0..2] Set failure flag\n" " 0=silent 1=printk 2=panic\n" " -F f=v Build rule: field name, operator(=,!=,<,>,<=,\n" " >=,&,&=) value\n" " -h Help\n" " -i Ignore errors when reading rules from file\n" " -k Set filter key on audit rule\n" " -l List rules\n" " -m text Send a user-space message\n" " -p [r|w|x|a] Set permissions filter on watch\n" " r=read, w=write, x=execute, a=attribute\n" " -q make subtree part of mount point's dir watches\n" " -r Set limit in messages/sec (0=none)\n" " -R read rules from file\n" " -s Report status\n" " -S syscall Build rule: syscall name or number\n" " --signal Send the specified signal to the daemon\n" " -t Trim directory watches\n" " -v Version\n" " -w Insert watch at \n" " -W Remove watch at \n" #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 " --loginuid-immutable Make loginuids unchangeable once set\n" #endif #if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME == 1 || \ HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME == 1 " --backlog_wait_time Set the kernel backlog_wait_time\n" #endif #if defined(HAVE_STRUCT_AUDIT_STATUS_FEATURE_BITMAP) " --reset-lost Reset the lost record counter\n" #endif #if HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL == 1 " --reset_backlog_wait_time_actual Reset the actual backlog wait time counter\n" #endif ); } static int lookup_filter(const char *str, int *filter) { *filter = audit_name_to_flag(str); if (*filter == AUDIT_FILTER_EXCLUDE) exclude = 1; if (*filter == -1) return 2; return 0; } static int lookup_action(const char *str, int *act) { if (strcmp(str, "always") == 0) *act = AUDIT_ALWAYS; else if (strcmp(str, "never") == 0) *act = AUDIT_NEVER; else if (strcmp(str, "possible") == 0) return 1; else return 2; return 0; } /* * Returns 0 ok, 1 deprecated action, 2 rule error, * 3 multiple rule insert/delete */ static int audit_rule_setup(char *opt, int *filter, int *act) { int rc; char *p; if (++multiple != 1) return 3; p = strchr(opt, ','); if (p == NULL || strchr(p+1, ',')) return 2; *p = 0; /* Try opt both ways */ if (lookup_action(opt, act) == 2) { rc = lookup_filter(opt, filter); if (rc != 0) { *p = ','; return rc; } } /* Repair the string */ *p = ','; opt = p+1; /* If flags are empty, p+1 must be the filter */ if (*filter == AUDIT_FILTER_UNSET) lookup_filter(opt, filter); else { rc = lookup_action(opt, act); if (rc != 0) return rc; } /* Make sure we set both */ if (*filter == AUDIT_FILTER_UNSET || *act == -1) return 2; return 0; } /* * This function will check the path before accepting it. It returns * 1 on error and 0 on success. */ static int check_path(const char *path) { char *ptr, *base; size_t nlen; size_t plen = strlen(path); if (plen >= PATH_MAX) { audit_msg(LOG_ERR, "The path passed for the watch is too big"); return 1; } if (path[0] != '/') { audit_msg(LOG_ERR, "The path must start with '/'"); return 1; } ptr = strdup(path); base = basename(ptr); nlen = strlen(base); free(ptr); if (nlen > NAME_MAX) { audit_msg(LOG_ERR, "The base name of the path is too big"); return 1; } /* These are warnings, not errors */ if (strstr(path, "..")) audit_msg(LOG_WARNING, "Warning - relative path notation is not supported"); if (strchr(path, '*') || strchr(path, '?')) audit_msg(LOG_WARNING, "Warning - wildcard notation is not supported"); return 0; } /* * Setup a watch. The "name" of the watch in userspace will be the to * the watch. When this potential watch reaches the kernel, it will resolve * down to (of terminating file or directory). * Returns a 1 on success & -1 on failure. */ static int audit_setup_watch_name(struct audit_rule_data **rulep, char *path) { int type = AUDIT_WATCH; size_t len; struct stat buf; if (check_path(path)) return -1; // Trim trailing '/' should they exist len = strlen(path); if (len > 2 && path[len-1] == '/') { while (path[len-1] == '/' && len > 1) { path[len-1] = 0; len--; } } if (stat(path, &buf) == 0) { if (S_ISDIR(buf.st_mode)) type = AUDIT_DIR; } /* FIXME: might want to check to see that rule is empty */ if (audit_add_watch_dir(type, rulep, path)) return -1; if (add != AUDIT_FILTER_UNSET) audit_msg(LOG_INFO, "Old style watch rules are slower"); return 1; } /* * Setup a watch permissions. * Returns a 1 on success & -1 on failure. */ static int audit_setup_perms(const char *opt) { unsigned int i, len, val = 0; len = strlen(opt); if (len > 4) { audit_msg(LOG_ERR, "permission %s is too long", opt); return -1; } for (i = 0; i < len; i++) { switch (tolower(opt[i])) { case 'r': val |= AUDIT_PERM_READ; break; case 'w': val |= AUDIT_PERM_WRITE; break; case 'x': val |= AUDIT_PERM_EXEC; break; case 'a': val |= AUDIT_PERM_ATTR; break; default: audit_msg(LOG_ERR, "Permission %c isn't supported", opt[i]); return -1; } } if (audit_update_watch_perms(rule_new, val) == 0) { _audit_permadded = 1; return 1; } return -1; } static int equiv_parse(char *optarg, char **mp, char **sub) { char *ptr = strchr(optarg, ','); if (ptr == NULL) return -1; // no comma *ptr = 0; ptr++; if (*ptr == 0) return -1; // ends with comma *mp = optarg; *sub = ptr; if (strchr(*sub, ',')) return -1; // too many commas return 0; } static int audit_request_rule_list(void) { if (audit_request_rules_list_data(fd) > 0) { list_requested = 1; get_reply(); return 1; } return 0; } static int check_rule_mismatch(int lineno, const char *option) { struct audit_rule_data tmprule; unsigned int old_audit_elf = _audit_elf; int rc = 0; switch (_audit_elf) { case AUDIT_ARCH_X86_64: _audit_elf = AUDIT_ARCH_I386; break; case AUDIT_ARCH_PPC64: _audit_elf = AUDIT_ARCH_PPC; break; case AUDIT_ARCH_S390X: _audit_elf = AUDIT_ARCH_S390; break; } char *ptr, *saved, *tmp = strdup(option); if (tmp == NULL) return -1; ptr = strtok_r(tmp, ",", &saved); memset(&tmprule, 0, sizeof(struct audit_rule_data)); while (ptr) { audit_rule_syscallbyname_data(&tmprule, ptr); ptr = strtok_r(NULL, ",", &saved); } if (memcmp(tmprule.mask, rule_new->mask, AUDIT_BITMASK_SIZE * sizeof(tmprule.mask[0]))) rc = 1; free(tmp); _audit_elf = old_audit_elf; if (rc) { if (lineno) audit_msg(LOG_WARNING, "WARNING - 32/64 bit syscall mismatch in line %d, you should specify an arch", lineno); else audit_msg(LOG_WARNING, "WARNING - 32/64 bit syscall mismatch, you should specify an arch"); } return 0; } #ifdef SYS_pidfd_open static int pidfd_open(int pid, unsigned int flags) { return syscall(SYS_pidfd_open, pid, flags); } static int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, unsigned int flags) { return syscall(SYS_pidfd_send_signal, pidfd, sig, info, flags); } // This function uses the new pidfd_ family of functions to send // the signal to auditd. If the signal is SIGTERM, it waits for auditd // to exit before returning. This is to prevent old and new daemons // from stepping on each other since auditd shutsdown slowly. static int sure_kill(int pid, int signal) { int rc = 0; int pidfd = pidfd_open(pid, 0); if (pidfd < 0) return -1; if (pidfd_send_signal(pidfd, signal, NULL, 0) < 0) { rc = -1; goto out; } if (signal == SIGTERM) { struct pollfd pollfd; pollfd.fd = pidfd; pollfd.events = POLLIN; int ready = poll(&pollfd, 1, -1); if (ready == -1) { perror("poll"); rc = -1; goto out; } // Check if it exited or errored if (!(pollfd.revents & POLLIN)) rc = -1; } out: close(pidfd); return rc; } #endif static int send_signal(const char *optarg) { int signal = 0, retval, i; int timeout = 40; /* loop has delay of .1 - so this is 4 seconds */ struct audit_reply rep; fd_set read_mask; FD_ZERO(&read_mask); FD_SET(fd, &read_mask); if (strcasecmp(optarg, "TERM") == 0 || strcasecmp(optarg, "stop") == 0) signal = SIGTERM; else if (strcasecmp(optarg, "HUP") == 0 || strcasecmp(optarg, "reload") == 0) signal = SIGHUP; else if (strcasecmp(optarg, "USR1") == 0 || strcasecmp(optarg, "rotate") == 0) signal = SIGUSR1; else if (strcasecmp(optarg, "USR2") == 0 || strcasecmp(optarg, "resume") == 0) signal = SIGUSR2; else if (strcasecmp(optarg, "CONT") == 0 || strcasecmp(optarg, "state") == 0) signal = SIGCONT; if (signal == 0) { audit_msg(LOG_ERR, "%s is an unsupported signal", optarg); exit(1); } // Request status so that we can find the pid retval = audit_request_status(fd); if (retval == -1) { if (errno == ECONNREFUSED) audit_msg(LOG_INFO, "The audit system is disabled"); exit(1); } // Receive the netlink info for (i = 0; i < timeout; i++) { struct timeval t; t.tv_sec = 0; t.tv_usec = 100000; /* .1 second */ do { retval = select(fd+1, &read_mask, NULL, NULL, &t); } while (retval < 0 && errno == EINTR); // We'll try to read just in case retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); if (retval > 0) { if (rep.type == NLMSG_ERROR && rep.error->error == 0) { i = 0; /* reset timeout */ continue; /* This was an ack */ } if (rep.type == NLMSG_NOOP) { i = 0; /* If getting more, reset timeout */ continue; } else if (rep.type == NLMSG_DONE) break; else if (rep.type == AUDIT_GET) { if (rep.status->pid == 0) { audit_msg(LOG_INFO, "Auditd is not running"); exit(2); } #ifdef SYS_pidfd_open retval = sure_kill(rep.status->pid, signal); #else retval = kill(rep.status->pid, signal); #endif if (retval < 0) { audit_msg(LOG_WARNING, "Failed sending signal to auditd (%s)", strerror(errno)); exit(1); } else return -2; } } } audit_msg(LOG_WARNING, "Failed sending signal to auditd (timeout)"); exit(1); } static int report_status(void) { int retval; retval = audit_request_status(fd); if (retval == -1) { if (errno == ECONNREFUSED) fprintf(stderr, "The audit system is disabled\n"); return -1; } get_reply(); retval = audit_request_features(fd); if (retval == -1) { // errno is EINVAL if the kernel does support features API if (errno == EINVAL) return -2; return -1; } get_reply(); return -2; } #ifdef WITH_IO_URING // return 0 on success and -1 if unknown op. static int parse_io_uring(const char *optarg) { if (strchr(optarg, ',')) { int retval = -1; char *saved, *ptr, *tmp = strdup(optarg); if (tmp == NULL) return retval; ptr = strtok_r(tmp, ",", &saved); while (ptr) { retval = audit_rule_io_uringbyname_data(rule_new, ptr); if (retval != 0) break; ptr = strtok_r(NULL, ",", &saved); } free(tmp); return retval; } return audit_rule_io_uringbyname_data(rule_new, optarg); } #endif static const struct option long_opts[] = { #if HAVE_DECL_AUDIT_FEATURE_VERSION == 1 {"loginuid-immutable", 0, NULL, 1}, #endif #if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME == 1 || \ HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME == 1 {"backlog_wait_time", 1, NULL, 2}, #endif #if defined(HAVE_STRUCT_AUDIT_STATUS_FEATURE_BITMAP) {"reset-lost", 0, NULL, 3}, #endif #if HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL == 1 {"reset_backlog_wait_time_actual", 0, NULL, 4}, #endif {"signal", 1, NULL, 5}, {NULL, 0, NULL, 0} }; typedef struct { int* count; // number of arguments char** vars; // arguments of the command int retval; // current return value int finish; // do we need to return after parsing this option? int lidx; // index of the long option (applicable to long opts only) int lineno; // line number in the file } opt_handler_params_t; static int opt_usage(opt_handler_params_t *args) { usage(); return OPT_ERROR_NO_REPLY; } static int opt_interpret(opt_handler_params_t *args) { ignore = 1; return OPT_SUCCESS_NO_REPLY; } static int opt_continue(opt_handler_params_t *args) { ignore = 1; continue_error = 1; return OPT_SUCCESS_NO_REPLY; } static int opt_status(opt_handler_params_t *args) { if (*(args->count) > 3) { audit_msg(LOG_ERR, "Too many options for status command"); return OPT_ERROR_NO_REPLY; } else if (optind == 2 && *(args->count) == 3) { if (strcmp(args->vars[optind], "-i") == 0) { interpret = 1; *(args->count) -= 1; } else { audit_msg(LOG_ERR, "Only -i option is allowed"); return OPT_ERROR_NO_REPLY; } } return report_status(); } static int opt_enabled(opt_handler_params_t *args) { int retval = args->retval; if (optarg && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "1") == 0) || (strcmp(optarg, "2") == 0))) { if (audit_set_enabled(fd, strtoul(optarg, NULL, 0)) > 0) audit_request_status(fd); else retval = OPT_ERROR_NO_REPLY; } else { audit_msg(LOG_ERR, "Enable must be 0, 1, or 2 was %s", optarg); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_failure(opt_handler_params_t *args) { int retval = args->retval; if (optarg && ((strcmp(optarg, "0") == 0) || (strcmp(optarg, "1") == 0) || (strcmp(optarg, "2") == 0))) { if (audit_set_failure(fd, strtoul(optarg, NULL, 0)) > 0) audit_request_status(fd); else { args->finish = 1; return OPT_ERROR_NO_REPLY; } } else { audit_msg(LOG_ERR, "Failure must be 0, 1, or 2 was %s", optarg); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_rate(opt_handler_params_t *args) { int retval = args->retval; if (optarg && isdigit((unsigned char)optarg[0])) { uint32_t rate; errno = 0; rate = strtoul(optarg, NULL, 0); if (errno) { args->finish = 1; audit_msg(LOG_ERR, "Error converting rate"); return OPT_ERROR_NO_REPLY; } if (audit_set_rate_limit(fd, rate) > 0) audit_request_status(fd); else { args->finish = 1; return OPT_ERROR_NO_REPLY; } } else { audit_msg(LOG_ERR, "Rate must be a numeric value was %s", optarg); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_backlog(opt_handler_params_t *args) { int retval = args->retval; if (optarg && isdigit((unsigned char)optarg[0])) { uint32_t limit; errno = 0; limit = strtoul(optarg, NULL, 0); if (errno) { audit_msg(LOG_ERR, "Error converting backlog"); args->finish = 1; return OPT_ERROR_NO_REPLY; } if (audit_set_backlog_limit(fd, limit) > 0) audit_request_status(fd); else { args->finish = 1; return OPT_ERROR_NO_REPLY; } } else { audit_msg(LOG_ERR, "Backlog must be a numeric value was %s", optarg); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_list(opt_handler_params_t *args) { int retval = args->retval; if (*(args->count) > 4) { audit_msg(LOG_ERR, "Wrong number of options for list request"); return OPT_ERROR_NO_REPLY; } if (*(args->count) == 3) { if (strcmp(args->vars[optind], "-i") == 0) { interpret = 1; *(args->count) -= 1; } else { audit_msg(LOG_ERR, "Only -k or -i options are allowed"); return OPT_ERROR_NO_REPLY; } } else if (*(args->count) == 4) { if (args->vars[optind] && strcmp(args->vars[optind], "-k") == 0) { strncat(key, args->vars[3], keylen); *(args->count) -= 2; } else { audit_msg(LOG_ERR, "Only -k or -i options are allowed"); return OPT_ERROR_NO_REPLY; } } if (audit_request_rule_list()) { list_requested = 1; retval = OPT_SUCCESS_NO_REPLY; } else retval = OPT_ERROR_NO_REPLY; return retval; } static int opt_append(opt_handler_params_t *args) { int retval = args->retval; if (strstr(optarg, "task") && _audit_syscalladded) { audit_msg(LOG_ERR, "Syscall auditing requested for task list"); retval = OPT_ERROR_NO_REPLY; } else { int rc = audit_rule_setup(optarg, &add, &action); if (rc == 3) { audit_msg(LOG_ERR, "Multiple rule insert/delete operations are not allowed\n"); retval = OPT_ERROR_NO_REPLY; } else if (rc == 2) { audit_msg(LOG_ERR, "Append rule - bad keyword %s", optarg); retval = OPT_ERROR_NO_REPLY; } else if (rc == 1) { audit_msg(LOG_ERR, "Append rule - possible is deprecated"); args->finish = 1; return OPT_DEPRECATED; /* deprecated - eat it */ } else retval = OPT_SUCCESS_RULE; /* success - please send */ } return retval; } static int opt_prepend(opt_handler_params_t *args) { int retval = args->retval, rc; rc = audit_rule_setup(optarg, &del, &action); if (rc == 3) { audit_msg(LOG_ERR, "Multiple rule insert/delete operations are not allowed"); retval = OPT_ERROR_NO_REPLY; } else if (rc == 2) { audit_msg(LOG_ERR, "Delete rule - bad keyword %s", optarg); retval = OPT_ERROR_NO_REPLY; } else if (rc == 1) { audit_msg(LOG_INFO, "Delete rule - possible is deprecated"); args->finish = 1; return OPT_DEPRECATED; /* deprecated - eat it */ } else retval = OPT_SUCCESS_RULE; /* success - please send */ return retval; } static int opt_delete(opt_handler_params_t *args) { int retval = args->retval, rc; rc = audit_rule_setup(optarg, &del, &action); if (rc == 3) { audit_msg(LOG_ERR, "Multiple rule insert/delete operations are not allowed"); retval = OPT_ERROR_NO_REPLY; } else if (rc == 2) { audit_msg(LOG_ERR, "Delete rule - bad keyword %s", optarg); retval = OPT_ERROR_NO_REPLY; } else if (rc == 1) { audit_msg(LOG_INFO, "Delete rule - possible is deprecated"); return OPT_DEPRECATED; /* deprecated - eat it */ } else retval = OPT_SUCCESS_RULE; /* success - please send */ return retval; } static int opt_syscall(opt_handler_params_t *args) { int retval = args->retval, rc; int unknown_arch = !_audit_elf; #ifdef WITH_IO_URING if (((add & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_URING_EXIT || (del & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_URING_EXIT)) { // Do io_uring op rc = parse_io_uring(optarg); switch (rc) { case 0: _audit_syscalladded = 1; retval = OPT_SUCCESS_RULE; /* success - please send */ break; case -1: audit_msg(LOG_ERR, "io_uring op unknown: %s", optarg); retval = OPT_ERROR_NO_REPLY; break; } return retval; } #endif /* Do some checking to make sure that we are not adding a * syscall rule to a list that does not make sense. */ if (((add & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_TASK || (del & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_TASK)) { audit_msg(LOG_ERR, "Error: syscall auditing being added to task list"); args->finish = 1; return OPT_ERROR_NO_REPLY; } else if (((add & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_USER || (del & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_USER)) { audit_msg(LOG_ERR, "Error: syscall auditing being added to user list"); args->finish = 1; return OPT_ERROR_NO_REPLY; } else if (((add & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_FS || (del & (AUDIT_FILTER_MASK | AUDIT_FILTER_UNSET)) == AUDIT_FILTER_FS)) { audit_msg(LOG_ERR, "Error: syscall auditing being added to filesystem list"); args->finish = 1; return OPT_ERROR_NO_REPLY; } else if (exclude) { audit_msg(LOG_ERR, "Error: syscall auditing cannot be put on exclude list"); args->finish = 1; return OPT_ERROR_NO_REPLY; } else { if (unknown_arch) { int machine; unsigned int elf; machine = audit_detect_machine(); if (machine < 0) { audit_msg(LOG_ERR, "Error detecting machine type"); args->finish = 1; return OPT_ERROR_NO_REPLY; } elf = audit_machine_to_elf(machine); if (elf == 0) { audit_msg(LOG_ERR, "Error looking up elf type %d", machine); args->finish = 1; return OPT_ERROR_NO_REPLY; } _audit_elf = elf; } } rc = _audit_parse_syscall(optarg, rule_new); switch (rc) { case 0: _audit_syscalladded = 1; if (unknown_arch && add != AUDIT_FILTER_UNSET) if (check_rule_mismatch(args->lineno, optarg) == -1) retval = OPT_ERROR_NO_REPLY; break; case -1: audit_msg(LOG_ERR, "Syscall name unknown: %s", optarg); retval = OPT_ERROR_NO_REPLY; break; case -2: audit_msg(LOG_ERR, "Elf type unknown: 0x%x", _audit_elf); retval = OPT_ERROR_NO_REPLY; break; case -3: // Error reported - do nothing here retval = OPT_ERROR_NO_REPLY; break; } return retval; } static int opt_field(opt_handler_params_t *args) { int retval = args->retval, rc; int flags = AUDIT_FILTER_UNSET; if (add != AUDIT_FILTER_UNSET) flags = add & AUDIT_FILTER_MASK; else if (del != AUDIT_FILTER_UNSET) flags = del & AUDIT_FILTER_MASK; // if the field is arch & there is a -t option...we can allow it else if ((optind >= *(args->count)) || (strstr(optarg, "arch=") == NULL) || (strcmp(args->vars[optind], "-t") != 0)) { audit_msg(LOG_ERR, "List must be given before field"); return OPT_ERROR_NO_REPLY; } // Keys need to get handled differently if (strncmp(optarg, "key=", 4) == 0) { optarg += 4; // goto process_keys; if ((strlen(optarg)+strlen(key)+(!!key[0])) > AUDIT_MAX_KEY_LEN) { audit_msg(LOG_ERR, "key option exceeds size limit"); retval = OPT_ERROR_NO_REPLY; } else { if (strchr(optarg, AUDIT_KEY_SEPARATOR)) audit_msg(LOG_ERR, "key %s has illegal character", optarg); if (key[0]) { // Add the separator if we need to strcat(key, key_sep); keylen--; } strncat(key, optarg, keylen); keylen = AUDIT_MAX_KEY_LEN - strlen(key); } return retval; } rc = audit_rule_fieldpair_data(&rule_new, optarg, flags); if (rc != 0) { audit_number_to_errmsg(rc, optarg); retval = OPT_ERROR_NO_REPLY; } else { if (rule_new->fields[rule_new->field_count - 1] == AUDIT_PERM) _audit_permadded = 1; if (rule_new->fields[rule_new->field_count - 1] == AUDIT_EXE) _audit_exeadded = 1; } return retval; } static int opt_compare(opt_handler_params_t *args) { int retval = args->retval, rc; int flags = AUDIT_FILTER_UNSET; if (add != AUDIT_FILTER_UNSET) flags = add & AUDIT_FILTER_MASK; else if (del != AUDIT_FILTER_UNSET) flags = del & AUDIT_FILTER_MASK; rc = audit_rule_interfield_comp_data(&rule_new, optarg, flags); if (rc != 0) { audit_number_to_errmsg(rc, optarg); retval = -1; } else { if (rule_new->fields[rule_new->field_count - 1] == AUDIT_PERM) _audit_permadded = 1; } return retval; } static int opt_message(opt_handler_params_t *args) { int retval = args->retval; if (*(args->count) > 3) { audit_msg(LOG_ERR, "The -m option must be only the only option and takes 1 parameter"); retval = OPT_ERROR_NO_REPLY; } else { const char* s = optarg; char* umsg; while (*s) { if (*s < 32) { audit_msg(LOG_ERR, "Illegal character in audit event"); args->finish = 1; return OPT_ERROR_NO_REPLY; } s++; } if (asprintf(&umsg, "text=%s", optarg) < 0) { audit_msg(LOG_ERR, "Can't create user event"); args->finish = 1; return OPT_ERROR_NO_REPLY; } if (audit_log_user_message(fd, AUDIT_USER, umsg, NULL, NULL, NULL, 1) <= 0) retval = OPT_ERROR_NO_REPLY; else { free(umsg); args->finish = 1; return OPT_SUCCESS_NO_REPLY; // success - no reply for this } free(umsg); } return retval; } static int opt_read_rules(opt_handler_params_t *args) { audit_msg(LOG_ERR, "Error - nested rule files not supported"); return OPT_ERROR_NO_REPLY; } static int opt_delete_all(opt_handler_params_t *args) { int retval = args->retval; if (*(args->count) > 4 || *(args->count) == 3) { audit_msg(LOG_ERR, "Wrong number of options for Delete all request"); return OPT_ERROR_NO_REPLY; } if (*(args->count) == 4) { if (strcmp(args->vars[optind], "-k") == 0) { strncat(key, args->vars[3], keylen); *(args->count) -= 2; } else { audit_msg(LOG_ERR, "Only the -k option is allowed"); return OPT_ERROR_NO_REPLY; } } retval = delete_all_rules(fd); if (retval == 0) { (void)audit_request_rule_list(); key[0] = 0; retval = -2; } return retval; } static int opt_watch(opt_handler_params_t *args) { int retval = args->retval; if (add != AUDIT_FILTER_UNSET || del != AUDIT_FILTER_UNSET) { audit_msg(LOG_ERR, "watch option can't be given with a syscall"); retval = OPT_ERROR_NO_REPLY; } else if (optarg) { add = AUDIT_FILTER_EXIT; action = AUDIT_ALWAYS; _audit_syscalladded = 1; retval = audit_setup_watch_name(&rule_new, optarg); } else { audit_msg(LOG_ERR, "watch option needs a path"); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_remove_watch(opt_handler_params_t *args) { int retval = args->retval; if (optarg) { del = AUDIT_FILTER_EXIT; action = AUDIT_ALWAYS; _audit_syscalladded = 1; retval = audit_setup_watch_name(&rule_new, optarg); } else { audit_msg(LOG_ERR, "watch option needs a path"); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_key(opt_handler_params_t *args) { int retval = args->retval; if (!(_audit_syscalladded || _audit_permadded || _audit_exeadded || _audit_filterfsadded) || (add == AUDIT_FILTER_UNSET && del == AUDIT_FILTER_UNSET)) { audit_msg(LOG_ERR, "key option needs a watch or syscall given prior to it"); return OPT_ERROR_NO_REPLY; } else if (!optarg) { audit_msg(LOG_ERR, "key option needs a value"); return OPT_ERROR_NO_REPLY; } // FIXME refactor this to a function // process_keys: if ((strlen(optarg) + strlen(key) + (!!key[0])) > AUDIT_MAX_KEY_LEN) { audit_msg(LOG_ERR, "key option exceeds size limit"); retval = -1; } else { if (strchr(optarg, AUDIT_KEY_SEPARATOR)) audit_msg(LOG_ERR, "key %s has illegal character", optarg); if (key[0]) { // Add the separator if we need to strcat(key, key_sep); keylen--; } strncat(key, optarg, keylen); keylen = AUDIT_MAX_KEY_LEN - strlen(key); } return retval; } static int opt_perms(opt_handler_params_t *args) { int retval = args->retval; if (add == AUDIT_FILTER_UNSET && del == AUDIT_FILTER_UNSET) { audit_msg(LOG_ERR, "permission option needs a watch given prior to it"); retval = OPT_ERROR_NO_REPLY; } else if (!optarg) { audit_msg(LOG_ERR, "permission option needs a filter"); retval = OPT_ERROR_NO_REPLY; } else retval = audit_setup_perms(optarg); return retval; } static int opt_mount(opt_handler_params_t *args) { int retval = args->retval; if (_audit_syscalladded) { audit_msg(LOG_ERR, "Syscall auditing requested for make equivalent"); retval = OPT_ERROR_NO_REPLY; } else { char *mp, *sub; retval = equiv_parse(optarg, &mp, &sub); if (retval < 0) { audit_msg(LOG_ERR, "Error parsing equivalent parts"); retval = OPT_ERROR_NO_REPLY; } else { retval = audit_make_equivalent(fd, mp, sub); if (retval <= 0) { retval = OPT_ERROR_NO_REPLY; } else { args->finish = 1; return OPT_SUCCESS_NO_REPLY; // success - no reply needed } } } return retval; } static int opt_trim(opt_handler_params_t *args) { int retval = audit_trim_subtrees(fd); if (retval <= 0) retval = OPT_ERROR_NO_REPLY; else { args->finish = 1; return OPT_SUCCESS_NO_REPLY; // success - no reply needed } return retval; } static int opt_version(opt_handler_params_t *args) { printf("auditctl version %s\n", VERSION); return OPT_SUCCESS_NO_REPLY; } static int opt_loginuid(opt_handler_params_t *args) { int retval = audit_set_loginuid_immutable(fd); if (retval <= 0) retval = OPT_ERROR_NO_REPLY; else return OPT_SUCCESS_NO_REPLY; // success - no reply for this return retval; } static int opt_wait_time(opt_handler_params_t *args) { int retval = args->retval; #if HAVE_DECL_AUDIT_VERSION_BACKLOG_WAIT_TIME == 1 || \ HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME == 1 if (optarg && isdigit((unsigned char)optarg[0])) { uint32_t bwt; errno = 0; bwt = strtoul(optarg, NULL, 0); if (errno) { audit_msg(LOG_ERR, "Error converting backlog_wait_time"); args->finish = 1; return OPT_ERROR_NO_REPLY; } if (audit_set_backlog_wait_time(fd, bwt) > 0) audit_request_status(fd); else { args->finish = 1; return OPT_ERROR_NO_REPLY; } } else { audit_msg(LOG_ERR, "Backlog_wait_time must be a numeric value was %s", optarg); retval = OPT_ERROR_NO_REPLY; } #else audit_msg(LOG_ERR, "backlog_wait_time is not supported on your kernel"); retval = OPT_ERROR_NO_REPLY; #endif return retval; } static int opt_reset_lost(opt_handler_params_t *args) { int retval = args->retval, rc; if ((rc = audit_reset_lost(fd)) >= 0) { audit_msg(LOG_INFO, "lost: %u", rc); return OPT_SUCCESS_NO_REPLY; } else { audit_number_to_errmsg(rc, long_opts[args->lidx].name); retval = OPT_ERROR_NO_REPLY; } return retval; } static int opt_reset_wait_time(opt_handler_params_t *args) { int retval = args->retval, rc; #if HAVE_DECL_AUDIT_STATUS_BACKLOG_WAIT_TIME_ACTUAL == 1 if ((rc = audit_reset_backlog_wait_time_actual(fd)) >= 0) { audit_msg(LOG_INFO, "backlog_wait_time_actual: %u", rc); args->finish = 1; return OPT_SUCCESS_NO_REPLY; } else { audit_number_to_errmsg(rc, long_opts[args->lidx].name); retval = OPT_ERROR_NO_REPLY; } #else audit_msg(LOG_ERR, "reset_backlog_wait_time_actual is not supported on your kernel"); retval = OPT_ERROR_NO_REPLY; #endif return retval; } static int opt_send_signal(opt_handler_params_t *args) { int retval = args->retval; retval = send_signal(optarg); return retval; } static int opt_default(opt_handler_params_t *args) { int retval = args->retval; char *bad_opt; if (optind >= 2) bad_opt = args->vars[optind - 1]; else bad_opt = " "; if (args->lineno) audit_msg(LOG_ERR, "Option %s on line %d is invalid", bad_opt, args->lineno); else audit_msg(LOG_ERR, "Option %s is invalid", bad_opt); retval = OPT_ERROR_NO_REPLY; return retval; } struct { int option; int (*handler)(opt_handler_params_t *args); } opt_handlers[] = { // short options {'h', opt_usage}, {'i', opt_interpret}, {'c', opt_continue}, {'s', opt_status}, {'e', opt_enabled}, {'f', opt_failure}, {'r', opt_rate}, {'b', opt_backlog}, {'l', opt_list}, {'a', opt_append}, {'A', opt_prepend}, {'d', opt_delete}, {'S', opt_syscall}, {'F', opt_field}, {'C', opt_compare}, {'m', opt_message}, {'R', opt_read_rules}, {'D', opt_delete_all}, {'w', opt_watch}, {'W', opt_remove_watch}, {'k', opt_key}, {'p', opt_perms}, {'q', opt_mount}, {'t', opt_trim}, {'v', opt_version}, // long options {1, opt_loginuid}, {2, opt_wait_time}, {3, opt_reset_lost}, {4, opt_reset_wait_time}, {5, opt_send_signal}, }; int handle_option(int option, opt_handler_params_t* args) { for (size_t i = 0; i < NUM_HANDLERS; i++) { if (opt_handlers[i].option == option) { return opt_handlers[i].handler(args); } } // Default handler if option is not found return opt_default(args); } /* * returns: -3 deprecated, -2 success - no reply, -1 error - noreply, * 0 success - reply, > 0 success - rule */ static int setopt(int count, int lineno, char *vars[]) { int c, lidx = 0; int retval = OPT_SUCCESS_REPLY; optind = 0; opterr = 0; key[0] = 0; keylen = AUDIT_MAX_KEY_LEN; /* Process arguments */ while ((retval >= 0) && (c = getopt_long(count, vars, "hicslDvtC:e:f:r:b:a:A:d:S:F:m:R:w:W:k:p:q:", long_opts, &lidx)) != EOF) { opt_handler_params_t params = {&count, vars, retval, 0, lidx, lineno}; retval = handle_option(c, ¶ms); /* if something went wrong during processing or we are done here */ if (params.finish) return retval; } /* catch extra args or errors where the user types "- s" */ if (optind == 1) retval = OPT_ERROR_NO_REPLY; else if ((optind < count) && (retval != OPT_ERROR_NO_REPLY)) { audit_msg(LOG_ERR, "parameter passed without an option given"); retval = OPT_ERROR_NO_REPLY; } /* See if we were adding a key */ if (key[0] && list_requested == 0) { int flags = 0; char* cmd = NULL; /* Get the flag */ if (add != AUDIT_FILTER_UNSET) flags = add & AUDIT_FILTER_MASK; else if (del != AUDIT_FILTER_UNSET) flags = del & AUDIT_FILTER_MASK; /* Build the command */ if (asprintf(&cmd, "key=%s", key) < 0) { cmd = NULL; audit_msg(LOG_ERR, "Out of memory adding key"); retval = OPT_ERROR_NO_REPLY; } else { /* Add this to the rule */ int ret = audit_rule_fieldpair_data(&rule_new, cmd, flags); if (ret != 0) { audit_number_to_errmsg(ret, cmd); retval = OPT_ERROR_NO_REPLY; } free(cmd); } } if (retval == OPT_ERROR_NO_REPLY && errno == ECONNREFUSED) audit_msg(LOG_ERR, "The audit system is disabled"); return retval; } static char *get_line(FILE *f, char *buf) { if (fgets_unlocked(buf, LINE_SIZE, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) *ptr = 0; return buf; } return NULL; } static void preprocess(char *buf) { unsigned int i = 0; bool esc_ctx = false; while (buf[i]) { if (buf[i] == '\\' && esc_ctx == false) esc_ctx = true; else { if (esc_ctx == true) { if (buf[i] == ' ') { buf[i] = 0x07; buf[i - 1] = 0x07; } else if (buf[i] == '\\') { buf[i] = 0x04; buf[i - 1] = 0x04; } esc_ctx = false; } } i++; } } static void postprocess(char *buf) { char *str = strdup(buf); char *pos1 = str; char *pos2 = buf; if (!str) return; while (*pos1) { if (*pos1 == 0x07) { *pos2 = ' '; pos1 += 2; pos2++; continue; } else if (*pos1 == 0x04) { *pos2 = '\\'; pos1 += 2; pos2++; continue; } *pos2 = *pos1; pos2++; pos1++; } *pos2 = 0; free(str); } /* * This function reads the given file line by line and executes the rule. * It returns 0 if everything went OK, 1 if there are problems before reading * the file, 2 if the rules file doesn't exist and it should, and -1 on * error conditions after executing some of the rules. It will abort reading * the file if it encounters any problems. */ static int fileopt(const char *file) { int i, tfd, rc, lineno = 1; struct stat st; FILE *f; char buf[LINE_SIZE]; /* Does the file exist? */ rc = open(file, O_RDONLY); if (rc < 0) { if (errno != ENOENT) { audit_msg(LOG_ERR,"Error opening %s (%s)", file, strerror(errno)); return 1; } audit_msg(LOG_ERR, "audit rules file %s doesn't exist", file); return 2; } tfd = rc; /* Is the file permissions sane? */ if (fstat(tfd, &st) < 0) { audit_msg(LOG_ERR, "Error fstat'ing %s (%s)", file, strerror(errno)); close(tfd); return 1; } if (!S_ISREG(st.st_mode)) { audit_msg(LOG_ERR, "Error - %s is not a regular file", file); close(tfd); return 1; } f = fdopen(tfd, "rm"); if (f == NULL) { audit_msg(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(tfd); return 1; } /* Read until eof, lineno starts as 1 */ while (get_line(f, buf)) { char *ptr, **fields; unsigned int idx=0, nf = (strlen(buf)/3) + 3; /* Weed out blank lines */ while (buf[idx] == ' ') idx++; if (buf[idx] == 0) { lineno++; continue; } preprocess(buf); ptr = audit_strsplit(buf); if (ptr == NULL) break; /* allow comments */ if (ptr[0] == '#') { lineno++; continue; } i = 0; fields = malloc(nf * sizeof(char *)); if (fields == NULL) { audit_msg(LOG_ERR, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); fclose(f); return 1; } fields[i++] = "auditctl"; fields[i++] = ptr; while( (ptr=audit_strsplit(NULL)) && (i < nf-1)) { postprocess(ptr); fields[i++] = ptr; } fields[i] = NULL; /* Parse it */ if (reset_vars()) { free(fields); fclose(f); return -1; } rc = setopt(i, lineno, fields); free(fields); /* handle reply or send rule */ if (rc != OPT_DEPRECATED) { if (handle_request(rc) == -1) { if (errno != ECONNREFUSED) audit_msg(LOG_ERR, "There was an error in line %d of %s", lineno, file); else { audit_msg(LOG_ERR, "The audit system is disabled"); fclose(f); return 0; } if (ignore == 0) { fclose(f); return -1; } if (continue_error) continue_error = -1; } } lineno++; } fclose(f); return 0; } /* Return 1 if ready, 0 otherwise */ static int is_ready(void) { if (audit_is_enabled(fd) == 2) { audit_msg(LOG_ERR, "The audit system is in immutable mode," " no rule changes allowed"); return 0; } else if (errno == ECONNREFUSED) { audit_msg(LOG_ERR, "The audit system is disabled"); return 0; } return 1; } int main(int argc, char *argv[]) { int retval = 1; set_aumessage_mode(MSG_STDERR, DBG_NO); if (argc == 1) { usage(); return 1; } #ifndef DEBUG /* Make sure we are root if we do anything except help */ if (!(argc == 2 && (strcmp(argv[1], "--help")==0 || strcmp(argv[1], "-h") == 0 || (strcmp(argv[1], "-l") == 0 && geteuid() == 0))) && !audit_can_control()) { audit_msg(LOG_WARNING, "You must be root to run this program."); return 4; } #endif /* Check where the rules are coming from: commandline or file */ if ((argc == 3) && (strcmp(argv[1], "-R") == 0)) { // If reading a file, its most likely start up. Send problems // to syslog where they will persist for later review set_aumessage_mode(MSG_SYSLOG, DBG_NO); fd = audit_open(); if (is_ready() == 0) return 1; else if (fileopt(argv[2])) { free(rule_new); return 1; } else { free(rule_new); if (continue_error < 0) return 1; return 0; } } else { if (reset_vars()) { free(rule_new); return 1; } retval = setopt(argc, 0, argv); if (retval == OPT_DEPRECATED) { free(rule_new); return 0; } } if (add != AUDIT_FILTER_UNSET || del != AUDIT_FILTER_UNSET) { fd = audit_open(); if (is_ready() == 0) { free(rule_new); return 1; } } retval = handle_request(retval); if (retval == -1) { if (errno != ECONNREFUSED) audit_msg(LOG_ERR, "There was an error while processing parameters"); else { audit_msg(LOG_ERR, "The audit system is disabled"); return 0; } } free(rule_new); return retval; } /* * This function is called after setopt to handle the return code. * On entry, status = 0 means just get the reply. Greater than 0 means we * are adding or deleting a rule or watch. -1 means an error occurred. * -2 means everything is OK and no reply needed. Even if there's an * error, we need to call this routine to close up the audit fd. * The return code from this function is 0 success and -1 error. */ static int handle_request(int status) { if (status == OPT_SUCCESS_REPLY) { if (_audit_syscalladded) { audit_msg(LOG_ERR, "Error - no list specified"); return -1; } get_reply(); } else if (status == OPT_SUCCESS_NO_REPLY) status = 0; // report success else if (status == OPT_SUCCESS_RULE) { int rc; if (add != AUDIT_FILTER_UNSET) { // if !task add syscall any if not specified if ((add & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK && _audit_syscalladded != 1) { audit_rule_syscallbyname_data( rule_new, "all"); } set_aumessage_mode(MSG_QUIET, DBG_NO); rc = audit_add_rule_data(fd, rule_new, add, action); set_aumessage_mode(MSG_STDERR, DBG_NO); /* Retry for legacy kernels */ if (rc < 0) { if (errno == EINVAL && rule_new->fields[0] == AUDIT_DIR) { rule_new->fields[0] = AUDIT_WATCH; rc = audit_add_rule_data(fd, rule_new, add, action); } else { audit_msg(LOG_ERR, "Error sending add rule data request (%s)", errno == EEXIST ? "Rule exists" : strerror(-rc)); } } } else if (del != AUDIT_FILTER_UNSET) { if ((del & AUDIT_FILTER_MASK) != AUDIT_FILTER_TASK && _audit_syscalladded != 1) { audit_rule_syscallbyname_data( rule_new, "all"); } set_aumessage_mode(MSG_QUIET, DBG_NO); rc = audit_delete_rule_data(fd, rule_new, del, action); set_aumessage_mode(MSG_STDERR, DBG_NO); /* Retry for legacy kernels */ if (rc < 0) { if (errno == EINVAL && rule_new->fields[0] == AUDIT_DIR) { rule_new->fields[0] = AUDIT_WATCH; rc = audit_delete_rule_data(fd,rule_new, del, action); } else { audit_msg(LOG_ERR, "Error sending delete rule data request (%s)", errno == EEXIST ? "Rule exists" : strerror(-rc)); } } } else { usage(); audit_close(fd); exit(1); } if (rc <= 0) status = -1; else status = 0; } else // OPT_ERROR_NO_REPLY or OPT_DEPRECATED status = -1; if (!list_requested) audit_close(fd); fd = -1; return status; } /* * A reply from the kernel is expected. Get and display it. */ static void get_reply(void) { int i, retval; int timeout = 40; /* loop has delay of .1 - so this is 4 seconds */ struct audit_reply rep; fd_set read_mask; FD_ZERO(&read_mask); FD_SET(fd, &read_mask); // Reset printing counter audit_print_init(); for (i = 0; i < timeout; i++) { struct timeval t; t.tv_sec = 0; t.tv_usec = 100000; /* .1 second */ do { retval=select(fd+1, &read_mask, NULL, NULL, &t); } while (retval < 0 && errno == EINTR); // We'll try to read just in case retval = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); if (retval > 0) { if (rep.type == NLMSG_ERROR && rep.error->error == 0) { i = 0; /* reset timeout */ continue; /* This was an ack */ } if ((retval = audit_print_reply(&rep, fd)) == 0) break; else i = 0; /* If getting more, reset timeout */ } } } audit-userspace-4.0.5/src/auditd-config.c000066400000000000000000001544311501761310600202760ustar00rootroot00000000000000/* auditd-config.c -- * Copyright 2004-2011,2013-14,2016,2018,2020-21 Red Hat Inc. * All Rights Reserved. * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include /* O_NOFOLLOW needs gnu defined */ #include #include #include /* INT_MAX */ #include #include "auditd-config.h" #include "libaudit.h" #include "private.h" #include "common.h" #define TCP_PORT_MAX 65535 /* Local prototypes */ struct nv_pair { const char *name; const char *value; const char *option; }; struct kw_pair { const char *name; int (*parser)(const struct nv_pair *, int, struct daemon_conf *); int max_options; }; struct nv_list { const char *name; int option; }; static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file); static int nv_split(char *buf, struct nv_pair *nv); static const struct kw_pair *kw_lookup(const char *val); static int local_events_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int write_logs_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int log_file_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int num_logs_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int log_group_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int qos_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int dispatch_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int name_format_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int name_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int max_log_size_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int max_log_size_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int log_format_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int flush_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int freq_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int space_left_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int space_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int action_mail_acct_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int verify_email_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int admin_space_left_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int admin_space_left_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int disk_full_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int disk_error_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int priority_boost_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int tcp_listen_port_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int tcp_listen_queue_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int tcp_max_per_addr_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int use_libwrap_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int tcp_client_ports_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int tcp_client_max_idle_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int transport_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int enable_krb5_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int krb5_principal_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int krb5_key_file_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int distribute_network_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int q_depth_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int overflow_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int max_restarts_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int plugin_dir_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int eoe_timeout_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int report_interval_parser(const struct nv_pair *nv, int line, struct daemon_conf *config); static int sanity_check(struct daemon_conf *config); static const struct kw_pair keywords[] = { {"local_events", local_events_parser, 0}, {"write_logs", write_logs_parser, 0 }, {"log_file", log_file_parser, 0 }, {"log_format", log_format_parser, 0 }, {"log_group", log_group_parser, 0 }, {"flush", flush_parser, 0 }, {"freq", freq_parser, 0 }, {"num_logs", num_logs_parser, 0 }, {"dispatcher", dispatch_parser, 0 }, {"name_format", name_format_parser, 0 }, {"name", name_parser, 0 }, {"disp_qos", qos_parser, 0 }, {"max_log_file", max_log_size_parser, 0 }, {"max_log_file_action", max_log_size_action_parser, 0 }, {"space_left", space_left_parser, 0 }, {"space_left_action", space_action_parser, 1 }, {"action_mail_acct", action_mail_acct_parser, 0 }, {"verify_email", verify_email_parser, 0 }, {"admin_space_left", admin_space_left_parser, 0 }, {"admin_space_left_action", admin_space_left_action_parser, 1 }, {"disk_full_action", disk_full_action_parser, 1 }, {"disk_error_action", disk_error_action_parser, 1 }, {"priority_boost", priority_boost_parser, 0 }, {"tcp_listen_port", tcp_listen_port_parser, 0 }, {"tcp_listen_queue", tcp_listen_queue_parser, 0 }, {"tcp_max_per_addr", tcp_max_per_addr_parser, 0 }, {"use_libwrap", use_libwrap_parser, 0 }, {"tcp_client_ports", tcp_client_ports_parser, 0 }, {"tcp_client_max_idle", tcp_client_max_idle_parser, 0 }, {"transport", transport_parser, 0 }, {"enable_krb5", enable_krb5_parser, 0 }, {"krb5_principal", krb5_principal_parser, 0 }, {"krb5_key_file", krb5_key_file_parser, 0 }, {"distribute_network", distribute_network_parser, 0 }, {"q_depth", q_depth_parser, 0 }, {"overflow_action", overflow_action_parser, 0 }, {"max_restarts", max_restarts_parser, 0 }, {"plugin_dir", plugin_dir_parser, 0 }, {"end_of_event_timeout", eoe_timeout_parser, 0 }, {"report_interval", report_interval_parser, 0 }, { NULL, NULL, 0 } }; static const struct nv_list log_formats[] = { {"raw", LF_RAW }, {"nolog", LF_NOLOG }, {"enriched", LF_ENRICHED }, { NULL, 0 } }; static const struct nv_list flush_techniques[] = { {"none", FT_NONE }, {"incremental", FT_INCREMENTAL }, {"incremental_async", FT_INCREMENTAL_ASYNC }, {"data", FT_DATA }, {"sync", FT_SYNC }, { NULL, 0 } }; static const struct nv_list failure_actions[] = { {"ignore", FA_IGNORE }, {"syslog", FA_SYSLOG }, {"rotate", FA_ROTATE }, {"email", FA_EMAIL }, {"exec", FA_EXEC }, {"suspend", FA_SUSPEND }, {"single", FA_SINGLE }, {"halt", FA_HALT }, { NULL, 0 } }; // Future ideas: e-mail, run command static const struct nv_list size_actions[] = { {"ignore", SZ_IGNORE }, {"syslog", SZ_SYSLOG }, {"suspend", SZ_SUSPEND }, {"rotate", SZ_ROTATE }, {"keep_logs", SZ_KEEP_LOGS}, { NULL, 0 } }; static const struct nv_list node_name_formats[] = { {"none", N_NONE }, {"hostname", N_HOSTNAME }, {"fqd", N_FQD }, {"numeric", N_NUMERIC }, {"user", N_USER }, { NULL, 0 } }; static const struct nv_list yes_no_values[] = { {"yes", 1 }, {"no", 0 }, { NULL, 0 } }; static const struct nv_list overflow_actions[] = { {"ignore", O_IGNORE }, {"syslog", O_SYSLOG }, {"suspend", O_SUSPEND }, {"single", O_SINGLE }, {"halt", O_HALT }, { NULL, 0 } }; static const struct nv_list transport_words[] = { {"tcp", T_TCP }, #ifdef USE_GSSAPI {"krb5", T_KRB5 }, #endif { NULL, 0 } }; const char *email_command = "/usr/lib/sendmail"; static int allow_links = 0; static const char *config_dir = NULL; static char *config_file = NULL; void set_allow_links(int allow) { allow_links = allow; } int set_config_dir(const char *val) { config_dir = strdup(val); if (config_dir == NULL) return 1; if (asprintf(&config_file, "%s/auditd.conf", config_dir) < 0) return 1; return 0; } /* * Set everything to its default value */ void clear_config(struct daemon_conf *config) { config->local_events = 1; config->sender_uid = 0; config->sender_pid = 0; config->sender_ctx = NULL; config->write_logs = 1; config->log_file = strdup("/var/log/audit/audit.log"); config->log_format = LF_ENRICHED; config->log_group = 0; config->priority_boost = 4; config->flush = FT_NONE; config->freq = 0; config->num_logs = 0L; config->node_name_format = N_NONE; config->node_name = NULL; config->max_log_size = 0L; config->max_log_size_action = SZ_IGNORE; config->space_left = 0L; config->space_left_percent = 0; config->space_left_action = FA_IGNORE; config->space_left_exe = NULL; config->action_mail_acct = strdup("root"); config->verify_email = 1; config->admin_space_left= 0L; config->admin_space_left_percent = 0; config->admin_space_left_action = FA_IGNORE; config->admin_space_left_exe = NULL; config->disk_full_action = FA_IGNORE; config->disk_full_exe = NULL; config->disk_error_action = FA_SYSLOG; config->disk_error_exe = NULL; config->tcp_listen_port = 0; config->tcp_listen_queue = 5; config->tcp_max_per_addr = 1; config->use_libwrap = 1; config->tcp_client_min_port = 0; config->tcp_client_max_port = TCP_PORT_MAX; config->tcp_client_max_idle = 0; config->transport = T_TCP; config->krb5_principal = NULL; config->krb5_key_file = NULL; config->distribute_network_events = 0; config->q_depth = 2000; config->overflow_action = O_SYSLOG; config->max_restarts = 10; config->plugin_dir = strdup("/etc/audit/plugins.d"); config->config_dir = NULL; config->end_of_event_timeout = EOE_TIMEOUT; config->report_interval = 0; } static log_test_t log_test = TEST_AUDITD; int load_config(struct daemon_conf *config, log_test_t lt) { int fd, rc, mode, lineno = 1; struct stat st; FILE *f; char buf[160]; clear_config(config); log_test = lt; if (config_file == NULL) config_file = strdup(CONFIG_FILE); /* open the file */ mode = O_RDONLY; if (allow_links == 0) mode |= O_NOFOLLOW; rc = open(config_file, mode); if (rc < 0) { if (errno != ENOENT) { audit_msg(LOG_ERR, "Error opening config file (%s)", strerror(errno)); return 1; } audit_msg(LOG_WARNING, "Config file %s doesn't exist, skipping", config_file); return 0; } fd = rc; /* check the file's permissions: owned by root, not world writable, * not symlink. */ audit_msg(LOG_DEBUG, "Config file %s opened for parsing", config_file); if (fstat(fd, &st) < 0) { audit_msg(LOG_ERR, "Error fstat'ing config file (%s)", strerror(errno)); close(fd); return 1; } if (st.st_uid != 0) { audit_msg(LOG_ERR, "Error - %s isn't owned by root", config_file); close(fd); return 1; } if ((st.st_mode & S_IWOTH) == S_IWOTH) { audit_msg(LOG_ERR, "Error - %s is world writable", config_file); close(fd); return 1; } if (!S_ISREG(st.st_mode)) { audit_msg(LOG_ERR, "Error - %s is not a regular file", config_file); close(fd); return 1; } /* it's ok, read line by line */ f = fdopen(fd, "rm"); if (f == NULL) { audit_msg(LOG_ERR, "Error - fdopen failed (%s)", strerror(errno)); close(fd); return 1; } while (get_line(f, buf, sizeof(buf), &lineno, config_file)) { // convert line into name-value pair const struct kw_pair *kw; struct nv_pair nv; rc = nv_split(buf, &nv); switch (rc) { case 0: // fine break; case 1: // not the right number of tokens. audit_msg(LOG_ERR, "Wrong number of arguments for line %d in %s", lineno, config_file); break; case 2: // no '=' sign audit_msg(LOG_ERR, "Missing equal sign for line %d in %s", lineno, config_file); break; default: // something else went wrong... audit_msg(LOG_ERR, "Unknown error for line %d in %s", lineno, config_file); break; } if (nv.name == NULL) { lineno++; continue; } if (nv.value == NULL) { fclose(f); audit_msg(LOG_ERR, "Not processing any more lines in %s", config_file); return 1; } /* identify keyword or error */ kw = kw_lookup(nv.name); if (kw->name == NULL) { audit_msg(LOG_ERR, "Unknown keyword \"%s\" in line %d of %s", nv.name, lineno, config_file); fclose(f); return 1; } /* Check number of options */ if (kw->max_options == 0 && nv.option != NULL) { audit_msg(LOG_ERR, "Keyword \"%s\" has invalid option " "\"%s\" in line %d of %s", nv.name, nv.option, lineno, config_file); fclose(f); return 1; } /* dispatch to keyword's local parser */ rc = kw->parser(&nv, lineno, config); if (rc != 0) { fclose(f); return 1; // local parser puts message out } lineno++; } fclose(f); if (lineno > 1) return sanity_check(config); return 0; } static char *get_line(FILE *f, char *buf, unsigned size, int *lineno, const char *file) { int too_long = 0; while (fgets_unlocked(buf, size, f)) { /* remove newline */ char *ptr = strchr(buf, 0x0a); if (ptr) { if (!too_long) { *ptr = 0; return buf; } // Reset and start with the next line too_long = 0; } else { // If a line is too long skip it. // Only output 1 warning if (!too_long) audit_msg(LOG_ERR, "Skipping line %d in %s: too long", *lineno, file); too_long = 1; } *lineno = *lineno + 1; } return NULL; } static int nv_split(char *buf, struct nv_pair *nv) { /* Get the name part */ char *ptr; nv->name = NULL; nv->value = NULL; nv->option = NULL; ptr = audit_strsplit(buf); if (ptr == NULL) return 0; /* If there's nothing, go to next line */ if (ptr[0] == '#') return 0; /* If there's a comment, go to next line */ nv->name = ptr; /* Check for a '=' */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; if (strcmp(ptr, "=") != 0) return 2; /* get the value */ ptr = audit_strsplit(NULL); if (ptr == NULL) return 1; nv->value = ptr; /* See if there's an option */ ptr = audit_strsplit(NULL); if (ptr) { nv->option = ptr; /* Make sure there's nothing else */ ptr = audit_strsplit(NULL); if (ptr) return 1; } /* Everything is OK */ return 0; } static const struct kw_pair *kw_lookup(const char *val) { int i = 0; while (keywords[i].name != NULL) { if (strcasecmp(keywords[i].name, val) == 0) break; i++; } return &keywords[i]; } static int local_events_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { unsigned long i; audit_msg(LOG_DEBUG, "local_events_parser called with: %s", nv->value); for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { config->local_events = yes_no_values[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int write_logs_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { unsigned long i; audit_msg(LOG_DEBUG, "write_logs_parser called with: %s", nv->value); for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { config->write_logs = yes_no_values[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int log_file_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { char *dir = NULL, *tdir; DIR *d; int fd, mode; struct stat buf; audit_msg(LOG_DEBUG, "log_file_parser called with: %s", nv->value); /* get dir from name. */ tdir = strdup(nv->value); if (tdir) dir = dirname(tdir); if (dir == NULL || strlen(dir) < 4) { // '/var' is shortest dirname audit_msg(LOG_ERR, "The directory name: %s is too short - line %d", dir, line); free((void *)tdir); return 1; } /* verify the directory path exists */ d = opendir(dir); if (d == NULL) { audit_msg(LOG_ERR, "Could not open dir %s (%s)", dir, strerror(errno)); free((void *)tdir); return 1; } free((void *)tdir); closedir(d); /* if the file exists, see that its regular, owned by root, * and not world anything */ if (log_test == TEST_AUDITD) mode = O_APPEND; else mode = O_RDONLY; fd = open(nv->value, mode); if (fd < 0) { if (errno == ENOENT) goto finish_up; // Will create the log later else { audit_msg(LOG_ERR, "Unable to open %s (%s)", nv->value, strerror(errno)); return 1; } } if (fstat(fd, &buf) < 0) { audit_msg(LOG_ERR, "Unable to stat %s (%s)", nv->value, strerror(errno)); close(fd); return 1; } close(fd); if (!S_ISREG(buf.st_mode)) { audit_msg(LOG_ERR, "%s is not a regular file", nv->value); return 1; } if (buf.st_uid != 0) { audit_msg(LOG_ERR, "%s is not owned by root", nv->value); return 1; } if ( (buf.st_mode & (S_IXUSR|S_IWGRP|S_IXGRP|S_IRWXO)) ) { audit_msg(LOG_WARNING, "%s permissions should be 0600 or 0640", nv->value); } if ( !(buf.st_mode & S_IWUSR) ) { audit_msg(LOG_WARNING, "audit log is not writable by owner"); } finish_up: free((void *)config->log_file); config->log_file = strdup(nv->value); if (config->log_file == NULL) return 1; return 0; } static int num_logs_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "num_logs_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (i > 999) { audit_msg(LOG_ERR, "num_logs must be 999 or less"); return 1; } config->num_logs = i; return 0; } static int qos_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_WARNING, "The disp_qos option is deprecated - line %d", line); return 0; } static int dispatch_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG, "dispatch_parser called with: %s", nv->value); audit_msg(LOG_WARNING, "The dispatcher option is deprecated - line %d", line); return 0; } static int name_format_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "name_format_parser called with: %s", nv->value); for (i=0; node_name_formats[i].name != NULL; i++) { if (strcasecmp(nv->value, node_name_formats[i].name) == 0) { config->node_name_format = node_name_formats[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int name_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG, "name_parser called with: %s", nv->value); if (nv->value == NULL) config->node_name = NULL; else config->node_name = strdup(nv->value); return 0; } static int max_log_size_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "max_log_size_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } config->max_log_size = i; return 0; } static int max_log_size_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "max_log_size_action_parser called with: %s", nv->value); for (i=0; size_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, size_actions[i].name) == 0) { config->max_log_size_action = size_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int log_format_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "log_format_parser called with: %s", nv->value); for (i=0; log_formats[i].name != NULL; i++) { if (strcasecmp(nv->value, log_formats[i].name) == 0) { config->log_format = log_formats[i].option; if (config->log_format == LF_NOLOG) { audit_msg(LOG_WARNING, "The NOLOG option to log_format is deprecated. Please use the write_logs option."); if (config->write_logs != 0) audit_msg(LOG_WARNING, "The NOLOG option is overriding the write_logs current setting."); config->write_logs = 0; } return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int log_group_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { gid_t gid = 0; audit_msg(LOG_DEBUG, "log_group_parser called with: %s", nv->value); if (isdigit((unsigned char)nv->value[0])) { errno = 0; gid = strtoul(nv->value,NULL,10); if (errno) { audit_msg(LOG_ERR, "Numeric group ID conversion error (%s) for %s - line %d\n", strerror(errno), nv->value, line); return 1; } } else { struct group *gr ; gr = getgrnam(nv->value); if (gr == NULL) { audit_msg(LOG_ERR, "Group ID is non-numeric and unknown (%s) - line %d\n", nv->value, line); return 1; } gid = gr->gr_gid; } config->log_group = gid; return 0; } static int flush_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "flush_parser called with: %s", nv->value); for (i=0; flush_techniques[i].name != NULL; i++) { if (strcasecmp(nv->value, flush_techniques[i].name) == 0) { config->flush = flush_techniques[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int freq_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "freq_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (i > INT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } config->freq = (unsigned int)i; return 0; } static int space_left_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { char *p, *ptr = (char *)nv->value; unsigned long i; int percent = 0; audit_msg(LOG_DEBUG, "space_left_parser called with: %s", nv->value); config->space_left_percent = 0; /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i]) && ptr[i] != '%') { audit_msg(LOG_ERR, "Value %c %s should only be numbers or percent - line %d", ptr[i],nv->value, line); return 1; } } /* Check for percent sign */ p = strchr(ptr, '%'); if (p) { percent = 1; *p = ' '; } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (percent) { if (i > 99) { audit_msg(LOG_ERR, "Percentages should be less than 100 - line %d", line); return 1; } config->space_left_percent = i; config->space_left = 0L; } else config->space_left = i; return 0; } static int check_exe_name(const char *val, int line) { struct stat buf; if (val == NULL) { audit_msg(LOG_ERR, "Executable path needed for line %d", line); return -1; } if (*val != '/') { audit_msg(LOG_ERR, "Absolute path needed for %s - line %d", val, line); return -1; } if (stat(val, &buf) < 0) { audit_msg(LOG_ERR, "Unable to stat %s (%s) - line %d", val, strerror(errno), line); return -1; } if (!S_ISREG(buf.st_mode)) { audit_msg(LOG_ERR, "%s is not a regular file - line %d", val, line); return -1; } if (buf.st_uid != 0) { audit_msg(LOG_ERR, "%s is not owned by root - line %d", val, line); return -1; } if ((buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != (S_IRWXU|S_IRGRP|S_IXGRP) && (buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) && (buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) && (buf.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != (S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) { audit_msg(LOG_ERR, "%s permissions should be 0750, 0755, 0555 or 0550 - line %d", val, line); return -1; } return 0; } static int space_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "space_action_parser called with: %s", nv->value); for (i=0; failure_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, failure_actions[i].name) == 0) { if (failure_actions[i].option == FA_EMAIL) { if (access(email_command, X_OK)) { audit_msg(LOG_ERR, "Email option is specified but %s doesn't seem executable.", email_command); } } else if (failure_actions[i].option == FA_EXEC) { if (check_exe_name(nv->option, line)) return 1; config->space_left_exe = strdup(nv->option); } else if (failure_actions[i].option == FA_HALT) { audit_msg(LOG_ERR, "The HALT option in space_left_action has been deprecated" " to prevent system instability from premature shutdowns."); return 1; } config->space_left_action = failure_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } const char *failure_action_to_str(unsigned int action) { if (action > FA_HALT) return "unknown"; return failure_actions[action].name; } // returns 0 if OK, 1 on temp error, 2 on permanent error static int validate_email(const char *acct) { int i, len; char *ptr1; if (acct == NULL) return 2; len = strlen(acct); if (len < 2) { audit_msg(LOG_ERR, "email: %s is too short, expecting at least 2 characters", acct); return 2; } // look for illegal char for (i=0; i ptr2)) { audit_msg(LOG_ERR, "email: %s should have . after @", acct); return 2; } memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; rc2 = getaddrinfo(ptr1+1, NULL, &hints, &ai); if (rc2 != 0) { if ((h_errno == HOST_NOT_FOUND) || (h_errno == NO_RECOVERY)) { audit_msg(LOG_ERR, "validate_email: failed looking up host for %s (%s)", ptr1+1, gai_strerror(rc2)); // FIXME: How can we tell that we truly have // a permanent failure and what is that? For // now treat all as temp failure. } else if (h_errno == TRY_AGAIN) { audit_msg(LOG_DEBUG, "validate_email: temporary failure looking up domain for %s", ptr1+1); } return 1; } freeaddrinfo(ai); } return 0; } static int action_mail_acct_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { char *tmail; audit_msg(LOG_DEBUG, "action_mail_acct_parser called with: %s", nv->value); tmail = strdup(nv->value); if (tmail == NULL) return 1; if (config->verify_email && validate_email(tmail) > 1) { free(tmail); return 1; } if (config->action_mail_acct) free((void *)config->action_mail_acct); config->action_mail_acct = tmail; return 0; } static int verify_email_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { unsigned long i; audit_msg(LOG_DEBUG, "verify_email_parser called with: %s", nv->value); for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { config->verify_email = yes_no_values[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int admin_space_left_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { char *p, *ptr = (char *)nv->value; unsigned long i; int percent = 0; audit_msg(LOG_DEBUG, "admin_space_left_parser called with: %s", nv->value); config->admin_space_left_percent = 0; /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i]) && ptr[i] != '%') { audit_msg(LOG_ERR, "Value %c %s should only be numbers or percent - line %d", ptr[i],nv->value, line); return 1; } } /* Check for percent sign */ p = strchr(ptr, '%'); if (p) { percent = 1; *p = ' '; } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (percent) { if (i > 99) { audit_msg(LOG_ERR, "Percentages should be less than 100 - line %d", line); return 1; } config->admin_space_left_percent = i; config->admin_space_left = 0L; } else config->admin_space_left = i; return 0; } static int admin_space_left_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "admin_space_left_action_parser called with: %s", nv->value); for (i=0; failure_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, failure_actions[i].name) == 0) { if (failure_actions[i].option == FA_EMAIL) { if (access(email_command, X_OK)) { audit_msg(LOG_ERR, "Email option is specified but %s doesn't seem executable.", email_command); } } else if (failure_actions[i].option == FA_EXEC) { if (check_exe_name(nv->option, line)) return 1; config->admin_space_left_exe = strdup(nv->option); } config->admin_space_left_action = failure_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int disk_full_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "disk_full_action_parser called with: %s", nv->value); for (i=0; failure_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, failure_actions[i].name) == 0) { if (failure_actions[i].option == FA_EMAIL) { audit_msg(LOG_ERR, "Illegal option %s for disk_full_action - line %d", nv->value, line); return 1; } else if (failure_actions[i].option == FA_EXEC) { if (check_exe_name(nv->option, line)) return 1; config->disk_full_exe = strdup(nv->option); } config->disk_full_action = failure_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int disk_error_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "disk_error_action_parser called with: %s", nv->value); for (i=0; failure_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, failure_actions[i].name) == 0) { if (failure_actions[i].option == FA_EMAIL || failure_actions[i].option == FA_ROTATE) { audit_msg(LOG_ERR, "Illegal option %s for disk_error_action - line %d", nv->value, line); return 1; } else if (failure_actions[i].option == FA_EXEC) { if (check_exe_name(nv->option, line)) return 1; config->disk_error_exe = strdup(nv->option); } config->disk_error_action = failure_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int priority_boost_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "priority_boost_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (i > INT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } config->priority_boost = (unsigned int)i; return 0; } static int tcp_listen_port_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "tcp_listen_port_parser called with: %s", nv->value); #ifndef USE_LISTENER audit_msg(LOG_DEBUG, "Listener support is not enabled, ignoring value at line %d", line); return 0; #else /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (i > TCP_PORT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } if (i < 1) { audit_msg(LOG_ERR, "Error - converted number (%s) is too small - line %d", nv->value, line); return 1; } config->tcp_listen_port = (unsigned int)i; return 0; #endif } static int tcp_listen_queue_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s", nv->value); #ifndef USE_LISTENER audit_msg(LOG_DEBUG, "Listener support is not enabled, ignoring value at line %d", line); return 0; #else /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range. While this value is technically unlimited, it's limited by the kernel, and we limit it here for sanity. */ if (i > TCP_PORT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } if (i < 1) { audit_msg(LOG_ERR, "Error - converted number (%s) is too small - line %d", nv->value, line); return 1; } config->tcp_listen_queue = (unsigned int)i; return 0; #endif } static int tcp_max_per_addr_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "tcp_max_per_addr_parser called with: %s", nv->value); #ifndef USE_LISTENER audit_msg(LOG_DEBUG, "Listener support is not enabled, ignoring value at line %d", line); return 0; #else /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range. While this value is technically unlimited, it's limited by the kernel, and we limit it here for sanity. */ if (i > 1024) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } if (i < 1) { audit_msg(LOG_ERR, "Error - converted number (%s) is too small - line %d", nv->value, line); return 1; } config->tcp_max_per_addr = (unsigned int)i; return 0; #endif } static int use_libwrap_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { unsigned long i; audit_msg(LOG_DEBUG, "use_libwrap_parser called with: %s", nv->value); for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { config->use_libwrap = yes_no_values[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int tcp_client_ports_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i, minv, maxv; const char *saw_dash = NULL; audit_msg(LOG_DEBUG, "tcp_listen_queue_parser called with: %s", nv->value); #ifndef USE_LISTENER audit_msg(LOG_DEBUG, "Listener support is not enabled, ignoring value at line %d", line); return 0; #else /* check that all chars are numbers, with an optional inclusive '-'. */ for (i=0; ptr[i]; i++) { if (i > 0 && ptr[i] == '-' && ptr[i+1] != '\0') { saw_dash = ptr + i; continue; } if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers, or " "two numbers separated by a dash - line %d", nv->value, line); return 1; } } for (; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers, or " "two numbers separated by a dash - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; maxv = minv = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (saw_dash) { maxv = strtoul(saw_dash + 1, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } } /* Check their ranges. */ if (minv > TCP_PORT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%ld) is too large - line %d", minv, line); return 1; } if (maxv > TCP_PORT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%ld) is too large - line %d", maxv, line); return 1; } if (minv > maxv) { audit_msg(LOG_ERR, "Error - converted range (%ld-%ld) is reversed - line %d", minv, maxv, line); return 1; } config->tcp_client_min_port = (unsigned int)minv; config->tcp_client_max_port = (unsigned int)maxv; return 0; #endif } static int tcp_client_max_idle_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "tcp_client_max_idle_parser called with: %s", nv->value); #ifndef USE_LISTENER audit_msg(LOG_DEBUG, "Listener support is not enabled, ignoring value at line %d", line); return 0; #else /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range. While this value is technically unlimited, it's limited by the kernel, and we limit it here for sanity. */ if (i > INT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } config->tcp_client_max_idle = (unsigned int)i; return 0; #endif } static int transport_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "transport_parser called with: %s", nv->value); for (i=0; transport_words[i].name != NULL; i++) { if (strcasecmp(nv->value, transport_words[i].name) == 0) { config->transport = transport_words[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int enable_krb5_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG, "enable_krb5_parser called with: %s", nv->value); #ifndef USE_GSSAPI audit_msg(LOG_DEBUG, "GSSAPI support is not enabled, ignoring value at line %d", line); return 0; #else unsigned long i; for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { if (yes_no_values[i].option == 1) config->transport = T_KRB5; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; #endif } static int krb5_principal_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG,"krb5_principal_parser called with: %s",nv->value); #ifndef USE_GSSAPI audit_msg(LOG_DEBUG, "GSSAPI support is not enabled, ignoring value at line %d", line); #else config->krb5_principal = strdup(nv->value); #endif return 0; } static int krb5_key_file_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG, "krb5_key_file_parser called with: %s", nv->value); #ifndef USE_GSSAPI audit_msg(LOG_DEBUG, "GSSAPI support is not enabled, ignoring value at line %d", line); #else config->krb5_key_file = strdup(nv->value); #endif return 0; } static int distribute_network_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { unsigned long i; audit_msg(LOG_DEBUG, "distribute_network_parser called with: %s", nv->value); for (i=0; yes_no_values[i].name != NULL; i++) { if (strcasecmp(nv->value, yes_no_values[i].name) == 0) { config->distribute_network_events = yes_no_values[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int q_depth_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "q_depth_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } if (i > 99999) { audit_msg(LOG_ERR, "q_depth must be 99999 or less"); return 1; } else if (i < 512) audit_msg(LOG_WARNING, "q_depth should be larger than 512 for safety margin"); config->q_depth = i; return 0; } static int overflow_action_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { int i; audit_msg(LOG_DEBUG, "overflow_action_parser called with: %s", nv->value); for (i=0; overflow_actions[i].name != NULL; i++) { if (strcasecmp(nv->value, overflow_actions[i].name) == 0) { config->overflow_action = overflow_actions[i].option; return 0; } } audit_msg(LOG_ERR, "Option %s not found - line %d", nv->value, line); return 1; } static int max_restarts_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "max_restarts_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned int */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } /* Check its range */ if (i > INT_MAX) { audit_msg(LOG_ERR, "Error - converted number (%s) is too large - line %d", nv->value, line); return 1; } config->max_restarts = (unsigned int)i; return 0; } static int plugin_dir_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { audit_msg(LOG_DEBUG, "plugin_dir_parser called with: %s", nv->value); if (nv->value == NULL) config->plugin_dir = NULL; else { size_t len = strlen(nv->value); free(config->plugin_dir); config->plugin_dir = malloc(len + 2); if (config->plugin_dir) { strcpy(config->plugin_dir, nv->value); if (len > 1 && config->plugin_dir[len - 1] != '/') config->plugin_dir[len] = '/'; config->plugin_dir[len + 1] = 0; } } return 0; } static int eoe_timeout_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { const char *ptr = nv->value; unsigned long i; audit_msg(LOG_DEBUG, "eoe_timeout_parser called with: %s", nv->value); /* check that all chars are numbers */ for (i=0; ptr[i]; i++) { if (!isdigit((unsigned char)ptr[i])) { audit_msg(LOG_ERR, "Value %s should only be numbers - line %d", nv->value, line); return 1; } } /* convert to unsigned long */ errno = 0; i = strtoul(nv->value, NULL, 10); if (errno) { audit_msg(LOG_ERR, "Error converting string to a number (%s) - line %d", strerror(errno), line); return 1; } config->end_of_event_timeout = i; return 0; } static int report_interval_parser(const struct nv_pair *nv, int line, struct daemon_conf *config) { long i; i = time_string_to_seconds(nv->value, "auditd", line); if (i < 0) return 1; if (i > 6*HOURS) audit_msg(LOG_WARNING, "Warning - report_interval is more than 6 hours apart - line %d", line); if (i > 40*DAYS) { audit_msg(LOG_ERR, "Error - report_interval (%s) is too large - line %d", nv->value, line); return 1; } config->report_interval = (unsigned int)i; return 0; } /* * Query file system and calculate in MB the given percentage is. * Returns 0 on error and a number otherwise. */ static unsigned long calc_percent(float percent, int fd) { int rc; struct statfs buf; rc = fstatfs(fd, &buf); if (rc == 0) { unsigned long free_space; // All blocks * percentage = free blocks threshold fsblkcnt_t free_blocks = buf.f_blocks * (percent/100.0); // That is then converted into megabytes and returned free_space = (buf.f_bsize * free_blocks) / MEGABYTE; return free_space; } return 0; } /* * This function translates a percentage of disk space to the * actual MB value for space left actions. */ void setup_percentages(struct daemon_conf *config, int fd) { if (!config->write_logs) return; if (config->daemonize != D_BACKGROUND) return; if (config->space_left_percent) config->space_left = calc_percent(config->space_left_percent, fd); if (config->admin_space_left_percent) config->admin_space_left = calc_percent(config->admin_space_left_percent, fd); if (config->space_left <= config->admin_space_left) audit_msg(LOG_ERR, "Error - space_left(%lu) must be larger than admin_space_left(%lu)", config->space_left, config->admin_space_left); } /* * This function is where we do the integrated check of the audit config * options. At this point, all fields have been read. Returns 0 if no * problems and 1 if problems detected. */ static int sanity_check(struct daemon_conf *config) { /* Error checking */ if (config->space_left_percent == 0 && config->admin_space_left_percent == 0 && config->space_left <= config->admin_space_left) { audit_msg(LOG_ERR, "Error - space_left(%lu) must be larger than admin_space_left(%lu)", config->space_left, config->admin_space_left); return 1; } if ((config->flush == FT_INCREMENTAL || config->flush == FT_INCREMENTAL_ASYNC) && config->freq == 0) { audit_msg(LOG_ERR, "Error - incremental flushing chosen, but 0 selected for freq"); return 1; } if (config->log_group != 0) { int rc = 0; char *path = strdup(config->log_file); const char *dir = dirname(path); if (dir && strcmp(dir, "/var/log") == 0) { audit_msg(LOG_ERR, "Error - log_file is directly in %s and chgrp" " will alter a system directory's permissions. Use" " another directory.", dir); rc = 1; } free(path); if (rc) return rc; } /* Warnings */ if (config->flush > FT_INCREMENTAL_ASYNC && config->freq != 0) { audit_msg(LOG_WARNING, "Warning - freq is non-zero and incremental flushing not selected."); } config->config_dir = config_dir; return 0; } const char *audit_lookup_format(int fmt) { int i; for (i=0; log_formats[i].name != NULL; i++) { if (log_formats[i].option == fmt) return log_formats[i].name; } return NULL; } int create_log_file(const char *val) { int fd; mode_t u; u = umask(S_IRWXO); fd = open(val, O_CREAT|O_EXCL|O_APPEND, S_IRUSR|S_IWUSR|S_IRGRP); if (fd < 0) audit_msg(LOG_ERR, "Unable to create %s (%s)", val, strerror(errno)); umask(u); return fd; } void free_config(struct daemon_conf *config) { free((void *)config->sender_ctx); free((void *)config->log_file); free((void *)config->node_name); free((void *)config->action_mail_acct); free((void *)config->space_left_exe); free((void *)config->admin_space_left_exe); free((void *)config->disk_full_exe); free((void *)config->disk_error_exe); free((void *)config->krb5_principal); free((void *)config->krb5_key_file); free((void *)config->plugin_dir); free((void *)config_dir); free(config_file); config_file = NULL; config->config_dir = NULL; } int resolve_node(struct daemon_conf *config) { int rc = 0; char tmp_name[255]; /* Get the host name representation */ switch (config->node_name_format) { case N_NONE: break; case N_HOSTNAME: if (gethostname(tmp_name, sizeof(tmp_name))) { audit_msg(LOG_ERR, "Unable to get machine name"); rc = -1; } else { // Remove any spaces char *p; while ((p = strchr(tmp_name, ' '))) *p = '_'; config->node_name = strdup(tmp_name); } break; case N_USER: if (config->node_name == NULL) { audit_msg(LOG_ERR, "User defined name missing"); rc = -1; } break; case N_FQD: if (gethostname(tmp_name, sizeof(tmp_name))) { audit_msg(LOG_ERR, "Unable to get machine name"); rc = -1; } else { int rc2; struct addrinfo *ai; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_CANONNAME; hints.ai_socktype = SOCK_STREAM; rc2 = getaddrinfo(tmp_name, NULL, &hints, &ai); if (rc2 != 0) { audit_msg(LOG_ERR, "Cannot resolve hostname %s (%s)", tmp_name, gai_strerror(rc2)); rc = -1; break; } config->node_name = strdup(ai->ai_canonname); freeaddrinfo(ai); } break; case N_NUMERIC: if (gethostname(tmp_name, sizeof(tmp_name))) { audit_msg(LOG_ERR, "Unable to get machine name"); rc = -1; } else { int rc2; struct addrinfo *ai; struct addrinfo hints; audit_msg(LOG_DEBUG, "Resolving numeric address for %s", tmp_name); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; rc2 = getaddrinfo(tmp_name, NULL, &hints, &ai); if (rc2) { audit_msg(LOG_ERR, "Cannot resolve hostname %s (%s)", tmp_name, gai_strerror(rc2)); rc = -1; break; } inet_ntop(ai->ai_family, ai->ai_family == AF_INET ? (void *) &((struct sockaddr_in *)ai->ai_addr)->sin_addr : (void *) &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, tmp_name, INET6_ADDRSTRLEN); freeaddrinfo(ai); config->node_name = strdup(tmp_name); } break; } if (rc == 0 && config->node_name) audit_msg(LOG_DEBUG, "Resolved node name: %s", config->node_name); return rc; } audit-userspace-4.0.5/src/auditd-config.h000066400000000000000000000077511501761310600203050ustar00rootroot00000000000000/* auditd-config.h -- * Copyright 2004-2009,2014,2016,2018 Red Hat Inc. * All Rights Reserved. * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #ifndef AUDITD_CONFIG_H #define AUDITD_CONFIG_H #include "libaudit.h" #include #define CONFIG_FILE "/etc/audit/auditd.conf" #define MEGABYTE 1048576UL // Define user space end of event timeout default (in seconds) #define EOE_TIMEOUT 2L typedef enum { D_FOREGROUND, D_BACKGROUND } daemon_t; typedef enum { LF_RAW, LF_NOLOG, LF_ENRICHED } logging_formats; typedef enum { FT_NONE, FT_INCREMENTAL, FT_INCREMENTAL_ASYNC, FT_DATA, FT_SYNC } flush_technique; typedef enum { FA_IGNORE, FA_SYSLOG, FA_ROTATE, FA_EMAIL, FA_EXEC, FA_SUSPEND, FA_SINGLE, FA_HALT } failure_action_t; typedef enum { SZ_IGNORE, SZ_SYSLOG, SZ_SUSPEND, SZ_ROTATE, SZ_KEEP_LOGS } size_action; typedef enum { TEST_AUDITD, TEST_SEARCH } log_test_t; typedef enum { N_NONE, N_HOSTNAME, N_FQD, N_NUMERIC, N_USER } node_t; typedef enum { O_IGNORE, O_SYSLOG, O_SUSPEND, O_SINGLE, O_HALT } overflow_action_t; typedef enum { T_TCP, T_TLS, T_KRB5, T_LABELED } transport_t; struct daemon_conf { daemon_t daemonize; unsigned int local_events; uid_t sender_uid; /* the uid for sender of sighup */ pid_t sender_pid; /* the pid for sender of sighup */ const char *sender_ctx; /* the context for the sender of sighup */ unsigned int write_logs; const char *log_file; logging_formats log_format; gid_t log_group; unsigned int priority_boost; flush_technique flush; unsigned int freq; unsigned int num_logs; node_t node_name_format; const char *node_name; unsigned long max_log_size; size_action max_log_size_action; unsigned long space_left; unsigned int space_left_percent; failure_action_t space_left_action; const char *space_left_exe; const char *action_mail_acct; unsigned int verify_email; unsigned long admin_space_left; unsigned int admin_space_left_percent; failure_action_t admin_space_left_action; const char *admin_space_left_exe; failure_action_t disk_full_action; const char *disk_full_exe; failure_action_t disk_error_action; const char *disk_error_exe; unsigned int report_interval; // Network receiving unsigned long tcp_listen_port; unsigned long tcp_listen_queue; unsigned long tcp_max_per_addr; int use_libwrap; unsigned long tcp_client_min_port; unsigned long tcp_client_max_port; unsigned long tcp_client_max_idle; int transport; const char *krb5_principal; const char *krb5_key_file; int distribute_network_events; // Dispatcher config unsigned int q_depth; overflow_action_t overflow_action; unsigned int max_restarts; char *plugin_dir; const char *config_dir; // Userspace configuration items unsigned long end_of_event_timeout; }; void set_allow_links(int allow); int set_config_dir(const char *val); int load_config(struct daemon_conf *config, log_test_t lt); void clear_config(struct daemon_conf *config); const char *audit_lookup_format(int fmt); int create_log_file(const char *val); int resolve_node(struct daemon_conf *config); void setup_percentages(struct daemon_conf *config, int fd); void init_config_manager(void); #ifdef AUDITD_EVENT_H int start_config_manager(struct auditd_event *e); #endif void free_config(struct daemon_conf *config); const char *failure_action_to_str(unsigned int action); #endif audit-userspace-4.0.5/src/auditd-dispatch.c000066400000000000000000000044661501761310600206320ustar00rootroot00000000000000/* auditd-dispatch.c -- * Copyright 2005-07,2013,2016-17 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Junji Kanemaru */ #include "config.h" #include #include #include #include #include #include #include #include "libaudit.h" #include "private.h" #include "auditd-dispatch.h" #include "libdisp.h" int dispatcher_pid(void) { return 0; } void dispatcher_reaped(void) { shutdown_dispatcher(); } /* This function returns 1 on error & 0 on success */ int init_dispatcher(const struct daemon_conf *config) { return libdisp_init(config); } void shutdown_dispatcher(void) { libdisp_shutdown(); } void reconfigure_dispatcher(const struct daemon_conf *config) { libdisp_reconfigure(config); } /* Returns -1 on err, 0 on success */ int dispatch_event(const struct audit_reply *rep, int protocol_ver) { event_t *e; if (!libdisp_active()) return 0; // Translate event into dispatcher format e = malloc(sizeof(event_t)); if (e == NULL) return -1; e->hdr.ver = protocol_ver; e->hdr.hlen = sizeof(struct audit_dispatcher_header); e->hdr.type = rep->type; // Network originating events have data at rep->message if (protocol_ver == AUDISP_PROTOCOL_VER) { e->hdr.size = rep->msg.nlh.nlmsg_len; memcpy(e->data, (void*)rep->msg.data, e->hdr.size); } else if (protocol_ver == AUDISP_PROTOCOL_VER2) { e->hdr.size = rep->len; memcpy(e->data, (void*)rep->message, e->hdr.size); } else { free(e); return 0; } return libdisp_enqueue(e); } audit-userspace-4.0.5/src/auditd-dispatch.h000066400000000000000000000023561501761310600206330ustar00rootroot00000000000000/* auditd-dispatch.h -- * Copyright 2005,2007,2013,2017 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef AUDITD_DISPATCH_H #define AUDITD_DISPATCH_H #include "auditd-config.h" int dispatcher_pid(void); void dispatcher_reaped(void); int init_dispatcher(const struct daemon_conf *config); void shutdown_dispatcher(void); void reconfigure_dispatcher(const struct daemon_conf *config); int dispatch_event(const struct audit_reply *rep, int protocol_ver); #endif audit-userspace-4.0.5/src/auditd-event.c000066400000000000000000001335741501761310600201570ustar00rootroot00000000000000/* auditd-event.c -- * Copyright 2004-08,2011,2013,2015-16,2018,2021 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include /* O_NOFOLLOW needs gnu defined */ #include #include #include #include #include #include #include /* POSIX_HOST_NAME_MAX */ #include /* toupper */ #include /* dirname */ #include "auditd-event.h" #include "auditd-dispatch.h" #include "auditd-listen.h" #include "libaudit.h" #include "private.h" #include "auparse.h" #include "auparse-idata.h" #include "common.h" #include /* This is defined in auditd.c */ #ifdef HAVE_ATOMIC extern ATOMIC_INT stop; #else extern volatile ATOMIC_INT stop; #endif extern void update_report_timer(unsigned int interval); /* Local function prototypes */ static void send_ack(const struct auditd_event *e, int ack_type, const char *msg); static void write_to_log(const struct auditd_event *e); static void check_log_file_size(void); static void check_space_left(void); static void do_space_left_action(int admin); static void do_disk_full_action(void); static void do_disk_error_action(const char *func, int err); static void fix_disk_permissions(void); static void check_excess_logs(void); static void rotate_logs_now(void); static void rotate_logs(unsigned int num_logs, unsigned int keep_logs); static void shift_logs(void); static int open_audit_log(void); static void change_runlevel(const char *level); static void safe_exec(const char *exe); static void reconfigure(struct auditd_event *e); static void init_flush_thread(void); /* Local Data */ static struct daemon_conf *config; static volatile int log_fd; static FILE *log_file = NULL; static unsigned int disk_err_warning = 0; static int fs_space_warning = 0; static int fs_admin_space_warning = 0; static int fs_space_left = 1; static int logging_suspended = 0; static unsigned int known_logs = 0; static const char *SINGLE = "1"; static const char *HALT = "0"; static char *format_buf = NULL; static off_t log_size = 0; static pthread_t flush_thread; static pthread_mutex_t flush_lock; static pthread_cond_t do_flush; static volatile int flush; static auparse_state_t *au = NULL; /* Local definitions */ #define MIN_SPACE_LEFT 24 static inline int from_network(const struct auditd_event *e) { if (e && e->ack_func) return 1; return 0; } int dispatch_network_events(void) { return config->distribute_network_events; } void write_logging_state(FILE *f) { fprintf(f, "writing to logs = %s\n", config->write_logs ? "yes" : "no"); if (config->daemonize == D_BACKGROUND && config->write_logs) { int rc; struct statfs buf; fprintf(f, "current log size = %llu KB\n", (long long unsigned)log_size/1024); fprintf(f, "max log size = %lu KB\n", config->max_log_size * (MEGABYTE/1024)); fprintf(f,"logs detected last rotate/shift = %u\n", known_logs); fprintf(f, "space left on partition = %s\n", fs_space_left ? "yes" : "no"); rc = fstatfs(log_fd, &buf); if (rc == 0) { fprintf(f, "Logging partition free space = %llu MB\n", (long long unsigned) (buf.f_bavail * buf.f_bsize)/MEGABYTE); fprintf(f, "space_left setting = %lu MB\n", config->space_left); fprintf(f, "admin_space_left setting = %lu MB\n", config->admin_space_left); } fprintf(f, "logging suspended = %s\n", logging_suspended ? "yes" : "no"); fprintf(f, "file system space action performed = %s\n", fs_space_warning ? "yes" : "no"); fprintf(f, "admin space action performed = %s\n", fs_admin_space_warning ? "yes" : "no"); fprintf(f, "disk error detected = %s\n", disk_err_warning ? "yes" : "no"); } } void shutdown_events(void) { // We are no longer processing events, sync the disk and close up. pthread_cancel(flush_thread); free((void *)format_buf); auparse_destroy_ext(au, AUPARSE_DESTROY_ALL); if (log_fd >= 0) fsync(log_fd); if (log_file) fclose(log_file); } int init_event(struct daemon_conf *conf) { /* Store the netlink descriptor and config info away */ config = conf; log_fd = -1; /* Now open the log */ if (config->daemonize == D_BACKGROUND) { fix_disk_permissions(); if (open_audit_log()) return 1; setup_percentages(config, log_fd); } else { log_fd = 1; // stdout log_file = fdopen(log_fd, "a"); if (log_file == NULL) { audit_msg(LOG_ERR, "Error setting up stdout descriptor (%s)", strerror(errno)); return 1; } /* Set it to line buffering */ setlinebuf(log_file); } if (config->daemonize == D_BACKGROUND) { check_log_file_size(); check_excess_logs(); /* At this stage, auditd is not fully initialized and operational. This means we can't notify the parent process that initialization is complete. However, if space_left_action is set to SINGLE, we must avoid switching to that runlevel. Before entering the SINGLE runlevel requires auditd to finish initialization. But auditd will not start properly or signal the init system that it has started, as it is blocked by the attempt to switch to single-user mode, resulting in a deadlock. */ // check_space_left(); } format_buf = (char *)malloc(FORMAT_BUF_LEN); if (format_buf == NULL) { audit_msg(LOG_ERR, "No memory for formatting, exiting"); if (log_file) fclose(log_file); log_file = NULL; return 1; } init_flush_thread(); return 0; } /* This tells the OS that pending writes need to get going. * Its only used when flush == incremental_async. */ static void *flush_thread_main(void *arg) { sigset_t sigs; /* This is a worker thread. Don't handle signals. */ sigemptyset(&sigs); sigaddset(&sigs, SIGTERM); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGUSR1); sigaddset(&sigs, SIGUSR2); sigaddset(&sigs, SIGCHLD); sigaddset(&sigs, SIGCONT); pthread_sigmask(SIG_SETMASK, &sigs, NULL); while (!AUDIT_ATOMIC_LOAD(stop)) { pthread_mutex_lock(&flush_lock); // In the event that the logging thread requests another // flush before the first completes, this simply turns // into a loop of fsyncs. while (flush == 0) { pthread_cond_wait(&do_flush, &flush_lock); if (AUDIT_ATOMIC_LOAD(stop)) { pthread_mutex_unlock(&flush_lock); return NULL; } } flush = 0; pthread_mutex_unlock(&flush_lock); if (log_fd >= 0) fsync(log_fd); } return NULL; } /* We setup the flush thread no matter what. This is incase a reconfig * changes from non incremental to incremental or vice versa. */ static void init_flush_thread(void) { pthread_mutex_init(&flush_lock, NULL); pthread_cond_init(&do_flush, NULL); flush = 0; pthread_create(&flush_thread, NULL, flush_thread_main, NULL); pthread_detach(flush_thread); } static void replace_event_msg(struct auditd_event *e, const char *buf) { if (buf) { size_t len = strlen(buf); if (len < MAX_AUDIT_MESSAGE_LENGTH - 1) e->reply.message = strdup(buf); else { // If too big, we must truncate the event due to API e->reply.message = strndup(buf, MAX_AUDIT_MESSAGE_LENGTH-1); len = MAX_AUDIT_MESSAGE_LENGTH; } // For network originating events, len should be used if (!from_network(e)) // V1 protocol msg size e->reply.msg.nlh.nlmsg_len = e->reply.len; e->reply.len = len; // V2 protocol msg size } } /* * This function will take an audit structure and return a * text buffer that's formatted for writing to disk. If there * is an error the return value is NULL. */ static const char *format_raw(const struct audit_reply *rep) { char *ptr; if (rep == NULL) { if (config->node_name_format != N_NONE) snprintf(format_buf, FORMAT_BUF_LEN - 32, "node=%s type=DAEMON_ERR op=format-raw msg=NULL res=failed", config->node_name); else snprintf(format_buf, MAX_AUDIT_MESSAGE_LENGTH, "type=DAEMON_ERR op=format-raw msg=NULL res=failed"); } else { int len, nlen; const char *type, *message; char unknown[32]; type = audit_msg_type_to_name(rep->type); if (type == NULL) { snprintf(unknown, sizeof(unknown), "UNKNOWN[%d]", rep->type); type = unknown; } if (rep->message == NULL) { message = "lost"; len = 4; } else { message = rep->message; len = rep->len; } // Note: This can truncate messages if // MAX_AUDIT_MESSAGE_LENGTH is too small if (config->node_name_format != N_NONE) nlen = snprintf(format_buf, FORMAT_BUF_LEN - 32, "node=%s type=%s msg=%.*s\n", config->node_name, type, len, message); else nlen = snprintf(format_buf, MAX_AUDIT_MESSAGE_LENGTH - 32, "type=%s msg=%.*s", type, len, message); /* Replace \n with space so it looks nicer. */ ptr = format_buf; while ((ptr = strchr(ptr, 0x0A)) != NULL) *ptr = ' '; /* Trim trailing space off since it wastes space */ if (format_buf[nlen-1] == ' ') format_buf[nlen-1] = 0; } return format_buf; } static int sep_done = 0; static int add_separator(unsigned int len_left) { if (sep_done == 0) { format_buf[FORMAT_BUF_LEN - len_left] = AUDIT_INTERP_SEPARATOR; sep_done++; return 1; } sep_done++; return 0; } // returns length used, 0 on error #define NAME_SIZE 64 static int add_simple_field(auparse_state_t *au, size_t len_left, int encode) { const char *value, *nptr; char *enc = NULL; char *ptr, field_name[NAME_SIZE]; size_t nlen, vlen, tlen; unsigned int i; int num; // prepare field name i = 0; nptr = auparse_get_field_name(au); while (*nptr && i < (NAME_SIZE - 1)) { field_name[i] = toupper(*nptr); i++; nptr++; } field_name[i] = 0; nlen = i; // get the translated value value = auparse_interpret_field(au); if (value == NULL) value = "?"; vlen = strlen(value); if (encode) { enc = audit_encode_nv_string(field_name, value, vlen); if (enc == NULL) return 0; tlen = 1 + strlen(enc) + 1; } else // calculate length to use tlen = 1 + nlen + 1 + vlen + 1; // If no room, do not truncate - just do nothing if (tlen >= len_left) { free(enc); return 0; } // Setup pointer ptr = &format_buf[FORMAT_BUF_LEN - len_left]; if (sep_done > 1) { *ptr = ' '; ptr++; num = 1; } else num = 0; // Add the field if (encode) { num += snprintf(ptr, tlen, "%s", enc); free(enc); } else num += snprintf(ptr, tlen, "%s=%s", field_name, value); return num; } /* * This function will take an audit structure and return a * text buffer that's formatted and enriched. If there is an * error the return value is NULL. */ static const char *format_enrich(const struct audit_reply *rep) { if (rep == NULL) { if (config->node_name_format != N_NONE) snprintf(format_buf, FORMAT_BUF_LEN - 32, "node=%s type=DAEMON_ERR op=format-enriched msg=NULL res=failed", config->node_name); else snprintf(format_buf, MAX_AUDIT_MESSAGE_LENGTH, "type=DAEMON_ERR op=format-enriched msg=NULL res=failed"); } else { int rc, rtype; size_t mlen, len; char *message; // Do raw format to get event started format_raw(rep); // How much room is left? mlen = strlen(format_buf); len = FORMAT_BUF_LEN - mlen; if (len <= MIN_SPACE_LEFT) return format_buf; // create copy to parse up format_buf[mlen] = 0x0A; format_buf[mlen+1] = 0; message = strdup(format_buf); format_buf[mlen] = 0; // init auparse if (au == NULL) { au = auparse_init(AUSOURCE_BUFFER, message); if (au == NULL) { free(message); return format_buf; } auparse_set_escape_mode(au, AUPARSE_ESC_RAW); auparse_set_eoe_timeout(config->end_of_event_timeout); } else auparse_new_buffer(au, message, mlen+1); sep_done = 0; // Loop over all fields while possible to add field rc = auparse_first_record(au); rtype = auparse_get_type(au); switch (rtype) { // Flush before adding to pickup new associations case AUDIT_ADD_USER: case AUDIT_ADD_GROUP: _auparse_flush_caches(); break; default: break; } while (rc > 0 && len > MIN_SPACE_LEFT) { // See what kind of field we have size_t vlen; int type = auparse_get_field_type(au); switch (type) { case AUPARSE_TYPE_UID: case AUPARSE_TYPE_GID: if (add_separator(len)) len--; vlen = add_simple_field(au, len, 1); len -= vlen; break; case AUPARSE_TYPE_SYSCALL: case AUPARSE_TYPE_ARCH: case AUPARSE_TYPE_SOCKADDR: if (add_separator(len)) len--; vlen = add_simple_field(au, len, 0); len -= vlen; break; default: break; } rc = auparse_next_field(au); } switch(rtype) { // Flush after modification to remove stale entries case AUDIT_USER_MGMT: case AUDIT_DEL_USER: case AUDIT_DEL_GROUP: case AUDIT_GRP_MGMT: _auparse_flush_caches(); break; default: break; } free(message); } return format_buf; } void format_event(struct auditd_event *e) { const char *buf; switch (config->log_format) { case LF_RAW: buf = format_raw(&e->reply); break; case LF_ENRICHED: buf = format_enrich(&e->reply); break; default: buf = NULL; break; } replace_event_msg(e, buf); } /* This function free's all memory associated with events */ void cleanup_event(struct auditd_event *e) { // Over in send_audit_event we sometimes have message pointing // into the middle of the reply allocation. Check for it. if (e->reply.message != e->reply.msg.data) free((void *)e->reply.message); free(e); } /* This function takes a reconfig event and sends it to the handler */ void enqueue_event(struct auditd_event *e) { e->ack_func = NULL; e->ack_data = NULL; e->sequence_id = 0; handle_event(e); cleanup_event(e); } /* This function allocates memory and fills the event fields with passed arguments. Caller must free memory. */ struct auditd_event *create_event(const char *msg, ack_func_type ack_func, void *ack_data, uint32_t sequence_id) { struct auditd_event *e; e = (struct auditd_event *)calloc(1, sizeof (*e)); if (e == NULL) { audit_msg(LOG_ERR, "Cannot allocate audit reply"); return NULL; } e->ack_func = ack_func; e->ack_data = ack_data; e->sequence_id = sequence_id; /* Network originating events need things adjusted to mimic netlink. */ if (from_network(e)) replace_event_msg(e, msg); return e; } /* This function takes the event and handles it. */ static unsigned int count = 0L; void handle_event(struct auditd_event *e) { if (e->reply.type == AUDIT_DAEMON_RECONFIG && e->ack_func == NULL) { reconfigure(e); if (config->write_logs == 0 && config->daemonize == D_BACKGROUND) return; format_event(e); } else if (e->reply.type == AUDIT_DAEMON_ROTATE) { rotate_logs_now(); if (config->write_logs == 0 && config->daemonize == D_BACKGROUND) return; } if (!logging_suspended && (config->write_logs || config->daemonize == D_FOREGROUND)) { write_to_log(e); /* See if we need to flush to disk manually */ if (config->flush == FT_INCREMENTAL || config->flush == FT_INCREMENTAL_ASYNC) { count++; if ((count % config->freq) == 0) { int rc; errno = 0; do { rc = fflush_unlocked(log_file); } while (rc < 0 && errno == EINTR); if (errno) { if (errno == ENOSPC && fs_space_left == 1) { fs_space_left = 0; do_disk_full_action(); } else //EIO is only likely failure mode do_disk_error_action("flush", errno); } if (config->daemonize == D_BACKGROUND) { if (config->flush == FT_INCREMENTAL) { /* EIO is only likely failure */ if (log_fd >= 0 && fsync(log_fd) != 0) { do_disk_error_action( "fsync", errno); } } else { pthread_mutex_lock(&flush_lock); flush = 1; pthread_cond_signal(&do_flush); pthread_mutex_unlock( &flush_lock); } } } } } else if (!config->write_logs && config->daemonize == D_BACKGROUND) send_ack(e, AUDIT_RMW_TYPE_ACK, ""); else if (logging_suspended) send_ack(e,AUDIT_RMW_TYPE_DISKERROR,"remote logging suspended"); } static void send_ack(const struct auditd_event *e, int ack_type, const char *msg) { if (from_network(e)) { unsigned char header[AUDIT_RMW_HEADER_SIZE]; AUDIT_RMW_PACK_HEADER(header, 0, ack_type, strlen(msg), e->sequence_id); e->ack_func(e->ack_data, header, msg); } } void resume_logging(void) { audit_msg(LOG_NOTICE, "Audit daemon is attempting to resume logging."); logging_suspended = 0; fs_space_left = 1; // User space action scripts cause fd to close // Need to reopen here to recreate the file if the // script deleted or moved it. if (log_file == NULL) { fix_disk_permissions(); if (open_audit_log()) { int saved_errno = errno; audit_msg(LOG_WARNING, "Could not reopen a log after resume logging"); logging_suspended = 1; do_disk_error_action("resume", saved_errno); } else check_log_file_size(); audit_msg(LOG_NOTICE, "Audit daemon resumed logging."); } disk_err_warning = 0; fs_space_warning = 0; fs_admin_space_warning = 0; } /* This function writes the given buf to the current log file */ static void write_to_log(const struct auditd_event *e) { int rc; int ack_type = AUDIT_RMW_TYPE_ACK; const char *msg = ""; /* write it to disk */ rc = fprintf(log_file, "%s\n", e->reply.message); /* error? Handle it */ if (rc < 0) { if (errno == ENOSPC) { ack_type = AUDIT_RMW_TYPE_DISKFULL; msg = "disk full"; send_ack(e, ack_type, msg); if (fs_space_left == 1) { fs_space_left = 0; do_disk_full_action(); } } else { int saved_errno = errno; ack_type = AUDIT_RMW_TYPE_DISKERROR; msg = "disk write error"; send_ack(e, ack_type, msg); do_disk_error_action("write", saved_errno); } } else { /* check log file size & space left on partition */ if (config->daemonize == D_BACKGROUND) { // If either of these fail, I consider it an // inconvenience as opposed to something that is // actionable. There may be some temporary condition // that the system recovers from. The real error // occurs on write. log_size += rc; check_log_file_size(); // Keep loose tabs on the free space if ((log_size % 8) < 3) check_space_left(); } if (fs_space_warning) ack_type = AUDIT_RMW_TYPE_DISKLOW; send_ack(e, ack_type, msg); disk_err_warning = 0; } } static void check_log_file_size(void) { /* did we cross the size limit? */ off_t sz = log_size / MEGABYTE; if (config->write_logs == 0) return; if (sz >= config->max_log_size && (config->daemonize == D_BACKGROUND)) { switch (config->max_log_size_action) { case SZ_IGNORE: break; case SZ_SYSLOG: audit_msg(LOG_ERR, "Audit daemon log file is larger than max size"); break; case SZ_SUSPEND: audit_msg(LOG_ERR, "Audit daemon is suspending logging due to logfile size."); // We need to close the file so that manual // intervention can move or delete the file. // We don't want to keep logging to a deleted // file. if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; break; case SZ_ROTATE: if (config->num_logs > 1) { audit_msg(LOG_INFO, "Audit daemon rotating log files"); rotate_logs(0, 0); } break; case SZ_KEEP_LOGS: audit_msg(LOG_INFO, "Audit daemon rotating log files with keep option"); shift_logs(); break; default: audit_msg(LOG_ALERT, "Audit daemon log file is larger than max size and unknown action requested"); break; } } } static void check_space_left(void) { int rc; struct statfs buf; if (log_fd < 0) return; rc = fstatfs(log_fd, &buf); if (rc == 0) { if (buf.f_bavail < 5) { /* we won't consume the last 5 blocks */ fs_space_left = 0; do_disk_full_action(); } else { unsigned long blocks; unsigned long block_size = buf.f_bsize; blocks = config->space_left * (MEGABYTE/block_size); if (buf.f_bavail < blocks) { if (fs_space_warning == 0) { do_space_left_action(0); // Allow unlimited rotation if (config->space_left_action != FA_ROTATE) fs_space_warning = 1; } } else if (fs_space_warning && config->space_left_action == FA_SYSLOG){ // Auto reset only if failure action is syslog fs_space_warning = 0; } blocks=config->admin_space_left * (MEGABYTE/block_size); if (buf.f_bavail < blocks) { if (fs_admin_space_warning == 0) { do_space_left_action(1); // Allow unlimited rotation if (config->admin_space_left_action != FA_ROTATE) fs_admin_space_warning = 1; } } else if (fs_admin_space_warning && config->admin_space_left_action == FA_SYSLOG) { // Auto reset only if failure action is syslog fs_admin_space_warning = 0; } } } else audit_msg(LOG_DEBUG, "fstatfs returned:%d, %s", rc, strerror(errno)); } extern int sendmail(const char *subject, const char *content, const char *mail_acct); static void do_space_left_action(int admin) { int action; char buffer[256]; const char *next_actions; // Select the appropriate action and generate a meaningful message // explaining what happens if disk space reaches a threshold or // becomes completely full. if (admin) { action = config->admin_space_left_action; snprintf(buffer, sizeof(buffer), "If the disk becomes full, audit will %s.", failure_action_to_str(config->disk_full_action)); } else { action = config->space_left_action; snprintf(buffer, sizeof(buffer), "If the admin space left threshold is reached, audit will %s. " "If the disk becomes full, audit will %s.", failure_action_to_str(config->admin_space_left_action), failure_action_to_str(config->disk_full_action)); } next_actions = buffer; // If space_left is reached and FA_HALT is set in any of these fields // we need to inform logged in users. if (config->admin_space_left_action == FA_HALT || config->disk_full_action == FA_HALT) { wall_message("The audit system is low on disk space and is now halting the system for admin corrective action."); } switch (action) { case FA_IGNORE: break; case FA_SYSLOG: audit_msg(LOG_ALERT, "Audit daemon is low on disk space for logging. %s", next_actions); break; case FA_ROTATE: if (config->num_logs > 1) { audit_msg(LOG_INFO, "Audit daemon rotating log files"); rotate_logs(0, 0); } break; case FA_EMAIL: { char content[512]; const char *subject; if (admin == 0) { subject = "Audit Disk Space Alert"; snprintf(content, sizeof(content), "The audit daemon is low on disk space for logging! Please take action\n" "to ensure no loss of service.\n" "%s", next_actions); } else { subject = "Audit Admin Space Alert"; snprintf(content, sizeof(content), "The audit daemon is very low on disk space for logging! Immediate action\n" "is required to ensure no loss of service.\n" "%s", next_actions); } sendmail(subject, content, config->action_mail_acct); audit_msg(LOG_ALERT, "%s", content); break; } case FA_EXEC: // Close the logging file in case the script zips or // moves the file. We'll reopen in sigusr2 handler if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; if (admin) safe_exec(config->admin_space_left_exe); else safe_exec(config->space_left_exe); break; case FA_SUSPEND: audit_msg(LOG_ALERT, "Audit daemon is suspending logging due to low disk space."); // We need to close the file so that manual // intervention can move or delete the file. We // don't want to keep logging to a deleted file. if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; break; case FA_SINGLE: audit_msg(LOG_ALERT, "The audit daemon is now changing the system to single user mode and exiting due to low disk space"); change_runlevel(SINGLE); AUDIT_ATOMIC_STORE(stop, 1); break; case FA_HALT: // Only available for admin audit_msg(LOG_ALERT, "The audit daemon is now halting the system and exiting due to low disk space"); change_runlevel(HALT); AUDIT_ATOMIC_STORE(stop, 1); break; default: audit_msg(LOG_ALERT, "Audit daemon is low on disk space for logging and unknown action requested"); break; } } static void do_disk_full_action(void) { audit_msg(LOG_ALERT, "Audit daemon has no space left on logging partition"); switch (config->disk_full_action) { case FA_IGNORE: case FA_SYSLOG: /* Message is syslogged above */ break; case FA_ROTATE: if (config->num_logs > 1) { audit_msg(LOG_INFO, "Audit daemon rotating log files"); rotate_logs(0, 0); } break; case FA_EXEC: // Close the logging file in case the script zips or // moves the file. We'll reopen in sigusr2 handler if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; safe_exec(config->disk_full_exe); break; case FA_SUSPEND: audit_msg(LOG_ALERT, "Audit daemon is suspending logging due to no space left on logging partition."); // We need to close the file so that manual // intervention can move or delete the file. We // don't want to keep logging to a deleted file. if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; break; case FA_SINGLE: audit_msg(LOG_ALERT, "The audit daemon is now changing the system to single user mode and exiting due to no space left on logging partition"); change_runlevel(SINGLE); AUDIT_ATOMIC_STORE(stop, 1); break; case FA_HALT: audit_msg(LOG_ALERT, "The audit daemon is now halting the system and exiting due to no space left on logging partition"); change_runlevel(HALT); AUDIT_ATOMIC_STORE(stop, 1); break; default: audit_msg(LOG_ALERT, "Unknown disk full action requested"); break; } } static void do_disk_error_action(const char *func, int err) { char text[128]; switch (config->disk_error_action) { case FA_IGNORE: break; case FA_SYSLOG: if (disk_err_warning < 5) { snprintf(text, sizeof(text), "%s: Audit daemon detected an error writing an event to disk (%s)", func, strerror(err)); audit_msg(LOG_ALERT, "%s", text); disk_err_warning++; } break; case FA_EXEC: // Close the logging file in case the script zips or // moves the file. We'll reopen in sigusr2 handler if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; safe_exec(config->disk_error_exe); break; case FA_SUSPEND: audit_msg(LOG_ALERT, "Audit daemon is suspending logging due to previously mentioned write error"); // We need to close the file so that manual // intervention can move or delete the file. We // don't want to keep logging to a deleted file. if (log_file) fclose(log_file); log_file = NULL; log_fd = -1; logging_suspended = 1; break; case FA_SINGLE: audit_msg(LOG_ALERT, "The audit daemon is now changing the system to single user mode and exiting due to previously mentioned write error"); change_runlevel(SINGLE); AUDIT_ATOMIC_STORE(stop, 1); break; case FA_HALT: audit_msg(LOG_ALERT, "The audit daemon is now halting the system and exiting due to previously mentioned write error."); change_runlevel(HALT); AUDIT_ATOMIC_STORE(stop, 1); break; default: audit_msg(LOG_ALERT, "Unknown disk error action requested"); break; } } static void rotate_logs_now(void) { /* Don't rotate in debug mode */ if (config->daemonize == D_FOREGROUND) return; if (config->max_log_size_action == SZ_KEEP_LOGS) shift_logs(); else rotate_logs(0, 0); } /* Check for and remove excess logs so that we don't run out of room */ static void check_excess_logs(void) { int rc; unsigned int i, len; char *name; // Only do this if rotate is the log size action // and we actually have a limit if (config->max_log_size_action != SZ_ROTATE || config->num_logs < 2) return; len = strlen(config->log_file) + 16; name = (char *)malloc(len); if (name == NULL) { /* Not fatal - just messy */ audit_msg(LOG_ERR, "No memory checking excess logs"); return; } // We want 1 beyond the normal logs i = config->num_logs; rc = 0; while (rc == 0) { snprintf(name, len, "%s.%u", config->log_file, i++); rc=unlink(name); if (rc == 0) audit_msg(LOG_NOTICE, "Log %s removed as it exceeds num_logs parameter", name); } free(name); } static void fix_disk_permissions(void) { char *path, *dir; unsigned int i, len; if (config == NULL || config->log_file == NULL) return; len = strlen(config->log_file) + 16; path = malloc(len); if (path == NULL) return; // Start with the directory strcpy(path, config->log_file); dir = dirname(path); if (chmod(dir,config->log_group ? S_IRWXU|S_IRGRP|S_IXGRP: S_IRWXU) < 0) audit_msg(LOG_WARNING, "Couldn't change access mode of " "%s (%s)", dir, strerror(errno)); if (chown(dir, 0, config->log_group ? config->log_group : 0) < 0) audit_msg(LOG_WARNING, "Couldn't change ownership of " "%s (%s)", dir, strerror(errno)); // Now, for each file... for (i = 1; i < config->num_logs; i++) { int rc; snprintf(path, len, "%s.%u", config->log_file, i); rc = chmod(path, config->log_group ? S_IRUSR|S_IRGRP : S_IRUSR); if (rc && errno == ENOENT) break; } // Now the current file chmod(config->log_file, config->log_group ? S_IWUSR|S_IRUSR|S_IRGRP : S_IWUSR|S_IRUSR); free(path); } static void rotate_logs(unsigned int num_logs, unsigned int keep_logs) { int rc, i; unsigned int len; char *oldname, *newname; /* Check that log rotation is enabled in the configuration file. There * is no need to check for max_log_size_action == SZ_ROTATE because * this could be invoked externally by receiving a USR1 signal, * independently on the action parameter. */ if (config->num_logs < 2 && !keep_logs){ audit_msg(LOG_NOTICE, "Log rotation disabled (num_logs < 2), skipping"); return; } /* Close audit file. fchmod and fchown errors are not fatal because we * already adjusted log file permissions and ownership when opening the * log file. */ if (log_fd >= 0) { if (fchmod(log_fd, config->log_group ? S_IRUSR|S_IRGRP : S_IRUSR) < 0){ audit_msg(LOG_WARNING, "Couldn't change permissions while " "rotating log file (%s)", strerror(errno)); } if (fchown(log_fd, 0, config->log_group) < 0) { audit_msg(LOG_WARNING, "Couldn't change ownership while " "rotating log file (%s)", strerror(errno)); } } if (log_file) { log_fd = -1; fclose(log_file); log_file = NULL; } /* Rotate */ len = strlen(config->log_file) + 16; oldname = (char *)malloc(len); if (oldname == NULL) { /* Not fatal - just messy */ audit_msg(LOG_ERR, "No memory rotating logs"); logging_suspended = 1; return; } newname = (char *)malloc(len); if (newname == NULL) { /* Not fatal - just messy */ audit_msg(LOG_ERR, "No memory rotating logs"); free(oldname); logging_suspended = 1; return; } /* If we are rotating, get number from config */ if (num_logs == 0) num_logs = config->num_logs; /* Handle this case first since it will not enter the for loop */ if (num_logs == 2) snprintf(oldname, len, "%s.1", config->log_file); known_logs = 0; for (i=(int)num_logs - 1; i>1; i--) { snprintf(oldname, len, "%s.%d", config->log_file, i-1); snprintf(newname, len, "%s.%d", config->log_file, i); /* if the old file exists */ rc = rename(oldname, newname); if (rc == -1 && errno != ENOENT) { // Likely errors: ENOSPC, ENOMEM, EBUSY int saved_errno = errno; audit_msg(LOG_ERR, "Error rotating logs from %s to %s (%s)", oldname, newname, strerror(errno)); if (saved_errno == ENOSPC && fs_space_left == 1) { fs_space_left = 0; do_disk_full_action(); } else do_disk_error_action("rotate", saved_errno); } else if (rc == 0 && known_logs == 0) known_logs = i + 1; } free(newname); /* At this point, oldname should point to lowest number - use it */ newname = oldname; rc = rename(config->log_file, newname); if (rc == -1 && errno != ENOENT) { // Likely errors: ENOSPC, ENOMEM, EBUSY int saved_errno = errno; audit_msg(LOG_ERR, "Error rotating logs from %s to %s (%s)", config->log_file, newname, strerror(errno)); if (saved_errno == ENOSPC && fs_space_left == 1) { fs_space_left = 0; do_disk_full_action(); } else do_disk_error_action("rotate2", saved_errno); /* At this point, we've failed to rotate the original log. * So, let's make the old log writable and try again next * time */ chmod(config->log_file, config->log_group ? S_IWUSR|S_IRUSR|S_IRGRP : S_IWUSR|S_IRUSR); } free(newname); /* open new audit file */ if (open_audit_log()) { int saved_errno = errno; audit_msg(LOG_CRIT, "Could not reopen a log after rotating."); logging_suspended = 1; do_disk_error_action("reopen", saved_errno); } } static unsigned int last_log = 1; static void shift_logs(void) { // The way this has to work is to start scanning from .1 up until // no file is found. Then do the rotate algorithm using that number // instead of log_max. unsigned int num_logs, len; char *name; len = strlen(config->log_file) + 16; name = (char *)malloc(len); if (name == NULL) { /* Not fatal - just messy */ audit_msg(LOG_ERR, "No memory shifting logs"); return; } // Find last log num_logs = last_log; while (num_logs) { snprintf(name, len, "%s.%u", config->log_file, num_logs); if (access(name, R_OK) != 0) break; num_logs++; } known_logs = num_logs; /* Our last known file disappeared, start over... */ if (num_logs <= last_log && last_log > 1) { audit_msg(LOG_WARNING, "Last known log disappeared (%s)", name); num_logs = last_log = 1; while (num_logs) { snprintf(name, len, "%s.%u", config->log_file, num_logs); if (access(name, R_OK) != 0) break; num_logs++; } audit_msg(LOG_INFO, "Next log to use will be %s", name); } last_log = num_logs; rotate_logs(num_logs+1, 1); free(name); } /* * This function handles opening a descriptor for the audit log * file and ensuring the correct options are applied to the descriptor. * It returns 0 on success and 1 on failure. */ static int open_audit_log(void) { int flags, lfd; if (config->write_logs == 0) return 0; flags = O_WRONLY|O_APPEND|O_NOFOLLOW|O_CLOEXEC; if (config->flush == FT_DATA) flags |= O_DSYNC; else if (config->flush == FT_SYNC) flags |= O_SYNC; // Likely errors for open: Almost anything // Likely errors on rotate: ENFILE, ENOMEM, ENOSPC retry: lfd = open(config->log_file, flags); if (lfd < 0) { if (errno == ENOENT) { lfd = create_log_file(config->log_file); if (lfd < 0) { audit_msg(LOG_CRIT, "Couldn't create log file %s (%s)", config->log_file, strerror(errno)); return 1; } close(lfd); lfd = open(config->log_file, flags); log_size = 0; } else if (errno == ENFILE) { // All system descriptors used, try again... goto retry; } if (lfd < 0) { audit_msg(LOG_CRIT, "Couldn't open log file %s (%s)", config->log_file, strerror(errno)); return 1; } } else { // Get initial size struct stat st; int rc = fstat(lfd, &st); if (rc == 0) log_size = st.st_size; else { close(lfd); return 1; } } if (fchmod(lfd, config->log_group ? S_IRUSR|S_IWUSR|S_IRGRP : S_IRUSR|S_IWUSR) < 0) { audit_msg(LOG_ERR, "Couldn't change permissions of log file (%s)", strerror(errno)); close(lfd); return 1; } if (fchown(lfd, 0, config->log_group) < 0) { audit_msg(LOG_ERR, "Couldn't change ownership of log file (%s)", strerror(errno)); close(lfd); return 1; } log_fd = lfd; log_file = fdopen(lfd, "a"); if (log_file == NULL) { audit_msg(LOG_CRIT, "Error setting up log descriptor (%s)", strerror(errno)); close(lfd); return 1; } /* Set it to line buffering */ setlinebuf(log_file); return 0; } static void change_runlevel(const char *level) { char *argv[3]; int pid; struct sigaction sa; static const char *init_pgm = "/sbin/init"; // In case of halt, we need to log the message before we halt if (strcmp(level, HALT) == 0) { write_to_console("audit: will try to change runlevel to %s\n", level); } pid = fork(); if (pid < 0) { audit_msg(LOG_ALERT, "Audit daemon failed to fork switching runlevels"); return; } if (pid) { /* Parent */ int status; // Wait until child exits if (waitpid(pid, &status, 0) < 0) { audit_msg(LOG_ALERT, "Audit daemon failed to wait for child"); return; } // Check if child exited normally, runlevel change was successful if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { write_to_console("audit: changed runlevel to %s\n", level); } return; } /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); argv[0] = (char *)init_pgm; argv[1] = (char *)level; argv[2] = NULL; execve(init_pgm, argv, NULL); audit_msg(LOG_ALERT, "Audit daemon failed to exec %s", init_pgm); exit(1); } static void safe_exec(const char *exe) { char *argv[2]; int pid; struct sigaction sa; if (exe == NULL) { audit_msg(LOG_ALERT, "Safe_exec passed NULL for program to execute"); return; } pid = fork(); if (pid < 0) { audit_msg(LOG_ALERT, "Audit daemon failed to fork doing safe_exec"); return; } if (pid) /* Parent */ return; /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); argv[0] = (char *)exe; argv[1] = NULL; execve(exe, argv, NULL); audit_msg(LOG_ALERT, "Audit daemon failed to exec %s", exe); exit(1); } static void reconfigure(struct auditd_event *e) { struct daemon_conf *nconf = e->reply.conf; struct daemon_conf *oconf = config; uid_t uid = nconf->sender_uid; pid_t pid = nconf->sender_pid; const char *ctx = nconf->sender_ctx; struct timeval tv; char txt[MAX_AUDIT_MESSAGE_LENGTH]; char date[40]; unsigned int seq_num; int need_size_check = 0, need_reopen = 0, need_space_check = 0; snprintf(txt, sizeof(txt), "config change requested by pid=%d auid=%u subj=%s", pid, uid, ctx); audit_msg(LOG_NOTICE, "%s", txt); /* Do the reconfiguring. These are done in a specific * order from least invasive to most invasive. We will * start with general system parameters. */ // start with disk error action. oconf->disk_error_action = nconf->disk_error_action; free((char *)oconf->disk_error_exe); oconf->disk_error_exe = nconf->disk_error_exe; disk_err_warning = 0; // number of logs oconf->num_logs = nconf->num_logs; // flush freq oconf->freq = nconf->freq; // priority boost if (oconf->priority_boost != nconf->priority_boost) { oconf->priority_boost = nconf->priority_boost; errno = 0; if (nice(-oconf->priority_boost)) ; /* Intentionally blank, we have to check errno */ if (errno) audit_msg(LOG_WARNING, "Cannot change priority in " "reconfigure (%s)", strerror(errno)); } // log format oconf->log_format = nconf->log_format; // Only update this if we are in background mode since // foreground mode writes to stderr. if ((oconf->write_logs != nconf->write_logs) && (oconf->daemonize == D_BACKGROUND)) { oconf->write_logs = nconf->write_logs; need_reopen = 1; } // log_group if (oconf->log_group != nconf->log_group) { oconf->log_group = nconf->log_group; need_reopen = 1; } // action_mail_acct if (strcmp(oconf->action_mail_acct, nconf->action_mail_acct)) { free((void *)oconf->action_mail_acct); oconf->action_mail_acct = nconf->action_mail_acct; } else free((void *)nconf->action_mail_acct); // node_name if (oconf->node_name_format != nconf->node_name_format || (oconf->node_name && nconf->node_name && strcmp(oconf->node_name, nconf->node_name) != 0)) { oconf->node_name_format = nconf->node_name_format; free((char *)oconf->node_name); oconf->node_name = nconf->node_name; } // network listener auditd_tcp_listen_reconfigure(nconf, oconf); // distribute network events oconf->distribute_network_events = nconf->distribute_network_events; // Dispatcher items oconf->q_depth = nconf->q_depth; oconf->overflow_action = nconf->overflow_action; oconf->max_restarts = nconf->max_restarts; if (oconf->plugin_dir != nconf->plugin_dir || (oconf->plugin_dir && nconf->plugin_dir && strcmp(oconf->plugin_dir, nconf->plugin_dir) != 0)) { free(oconf->plugin_dir); oconf->plugin_dir = nconf->plugin_dir; } /* At this point we will work on the items that are related to * a single log file. */ // max logfile action if (oconf->max_log_size_action != nconf->max_log_size_action) { oconf->max_log_size_action = nconf->max_log_size_action; need_size_check = 1; } // max log size if (oconf->max_log_size != nconf->max_log_size) { oconf->max_log_size = nconf->max_log_size; need_size_check = 1; } if (need_size_check) { logging_suspended = 0; check_log_file_size(); } // flush technique if (oconf->flush != nconf->flush) { oconf->flush = nconf->flush; need_reopen = 1; } // logfile if (strcmp(oconf->log_file, nconf->log_file)) { free((void *)oconf->log_file); oconf->log_file = nconf->log_file; need_reopen = 1; need_space_check = 1; // might be on new partition } else free((void *)nconf->log_file); if (need_reopen) { if (log_file) fclose(log_file); log_file = NULL; fix_disk_permissions(); if (open_audit_log()) { int saved_errno = errno; audit_msg(LOG_ERR, "Could not reopen a log after reconfigure"); logging_suspended = 1; // Likely errors: ENOMEM, ENOSPC do_disk_error_action("reconfig", saved_errno); } else { logging_suspended = 0; check_log_file_size(); } } /* At this point we will start working on items that are * related to the amount of space on the partition. */ // space left if (oconf->space_left != nconf->space_left) { oconf->space_left = nconf->space_left; need_space_check = 1; } // space left percent if (oconf->space_left_percent != nconf->space_left_percent) { oconf->space_left_percent = nconf->space_left_percent; need_space_check = 1; } // space left action if (oconf->space_left_action != nconf->space_left_action) { oconf->space_left_action = nconf->space_left_action; need_space_check = 1; } // space left exe if (oconf->space_left_exe || nconf->space_left_exe) { if (nconf->space_left_exe == NULL) ; /* do nothing if new one is blank */ else if (oconf->space_left_exe == NULL && nconf->space_left_exe) need_space_check = 1; else if (strcmp(oconf->space_left_exe, nconf->space_left_exe)) need_space_check = 1; free((char *)oconf->space_left_exe); oconf->space_left_exe = nconf->space_left_exe; } // admin space left if (oconf->admin_space_left != nconf->admin_space_left) { oconf->admin_space_left = nconf->admin_space_left; need_space_check = 1; } // admin space left percent if (oconf->admin_space_left_percent != nconf->admin_space_left_percent){ oconf->admin_space_left_percent = nconf->admin_space_left_percent; need_space_check = 1; } // admin space action if (oconf->admin_space_left_action != nconf->admin_space_left_action) { oconf->admin_space_left_action = nconf->admin_space_left_action; need_space_check = 1; } // admin space left exe if (oconf->admin_space_left_exe || nconf->admin_space_left_exe) { if (nconf->admin_space_left_exe == NULL) ; /* do nothing if new one is blank */ else if (oconf->admin_space_left_exe == NULL && nconf->admin_space_left_exe) need_space_check = 1; else if (strcmp(oconf->admin_space_left_exe, nconf->admin_space_left_exe)) need_space_check = 1; free((char *)oconf->admin_space_left_exe); oconf->admin_space_left_exe = nconf->admin_space_left_exe; } // disk full action if (oconf->disk_full_action != nconf->disk_full_action) { oconf->disk_full_action = nconf->disk_full_action; need_space_check = 1; } // disk full exe if (oconf->disk_full_exe || nconf->disk_full_exe) { if (nconf->disk_full_exe == NULL) ; /* do nothing if new one is blank */ else if (oconf->disk_full_exe == NULL && nconf->disk_full_exe) need_space_check = 1; else if (strcmp(oconf->disk_full_exe, nconf->disk_full_exe)) need_space_check = 1; free((char *)oconf->disk_full_exe); oconf->disk_full_exe = nconf->disk_full_exe; } // report interval if (oconf->report_interval != nconf->report_interval) { oconf->report_interval = nconf->report_interval; update_report_timer(oconf->report_interval); } if (need_space_check) { /* note save suspended flag, then do space_left. If suspended * is still 0, then copy saved suspended back. This avoids * having to call check_log_file_size to restore it. */ int saved_suspend = logging_suspended; setup_percentages(oconf, log_fd); fs_space_warning = 0; fs_admin_space_warning = 0; fs_space_left = 1; logging_suspended = 0; check_excess_logs(); check_space_left(); if (logging_suspended == 0) logging_suspended = saved_suspend; } reconfigure_dispatcher(oconf); // Next document the results srand(time(NULL)); seq_num = rand()%10000; if (gettimeofday(&tv, NULL) == 0) { snprintf(date, sizeof(date), "audit(%lld.%03u:%u)", (long long int)tv.tv_sec, (unsigned)(tv.tv_usec/1000), seq_num); } else { snprintf(date, sizeof(date), "audit(%lld.%03d:%u)", (long long int)time(NULL), 0, seq_num); } e->reply.type = AUDIT_DAEMON_CONFIG; e->reply.len = snprintf(e->reply.msg.data, MAX_AUDIT_MESSAGE_LENGTH-2, "%s: op=reconfigure state=changed auid=%u pid=%d subj=%s res=success", date, uid, pid, ctx ); e->reply.message = e->reply.msg.data; free((char *)ctx); } audit-userspace-4.0.5/src/auditd-event.h000066400000000000000000000032571501761310600201560ustar00rootroot00000000000000/* auditd-event.h -- * Copyright 2004,2005,2008,2016,2018 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef AUDITD_EVENT_H #define AUDITD_EVENT_H #include #include "libaudit.h" typedef void (*ack_func_type)(void *ack_data, const unsigned char *header, const char *msg); struct auditd_event { struct audit_reply reply; ack_func_type ack_func; void *ack_data; unsigned long sequence_id; }; #include "auditd-config.h" int dispatch_network_events(void); void write_logging_state(FILE *f); void shutdown_events(void); int init_event(struct daemon_conf *config); void resume_logging(void); void cleanup_event(struct auditd_event *e); void format_event(struct auditd_event *e); void enqueue_event(struct auditd_event *e); void handle_event(struct auditd_event *e); struct auditd_event *create_event(const char *msg, ack_func_type ack_func, void *ack_data, uint32_t sequence_id); #endif audit-userspace-4.0.5/src/auditd-listen.c000066400000000000000000000765171501761310600203370ustar00rootroot00000000000000/* auditd-listen.c -- * Copyright 2008,2009,2011,2016,2018 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * DJ Delorie * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include #include #include #include /* O_NOFOLLOW needs gnu defined */ #include #include #include /* INT_MAX */ #include #include #include #include #ifdef HAVE_LIBWRAP #include #endif #ifdef USE_GSSAPI #include #include #include #endif #include "libaudit.h" #include "auditd-event.h" #include "auditd-config.h" #include "private.h" #include "ev.h" extern int send_audit_event(int type, const char *str); #define DEFAULT_BUF_SZ 192 typedef struct ev_tcp { struct ev_io io; struct sockaddr_storage addr; struct ev_tcp *next, *prev; unsigned int bufptr; int client_active; #ifdef USE_GSSAPI /* This holds the negotiated security context for this client. */ gss_ctx_id_t gss_context; char *remote_name; int remote_name_len; #endif unsigned char buffer [MAX_AUDIT_MESSAGE_LENGTH + 17]; } ev_tcp; #define N_SOCKS 4 static int listen_socket[N_SOCKS]; static int nlsocks; static struct ev_io tcp_listen_watcher; static struct ev_periodic periodic_watcher; static unsigned min_port, max_port, max_per_addr; static int use_libwrap = 1; static int transport = T_TCP; static char msgbuf[MAX_AUDIT_MESSAGE_LENGTH + 1]; static struct ev_tcp *client_chain = NULL; #ifdef USE_GSSAPI /* This is our global credentials */ static gss_cred_id_t server_creds; // This is used to hold our own private key static char *my_service_name, *my_gss_realm; #define USE_GSS (transport == T_KRB5) #endif static char *sockaddr_to_string(const struct sockaddr_storage *addr) { static char buf[INET6_ADDRSTRLEN]; inet_ntop(addr->ss_family, addr->ss_family == AF_INET ? (void *) &((struct sockaddr_in *)addr)->sin_addr : (void *) &((struct sockaddr_in6 *)addr)->sin6_addr, buf, INET6_ADDRSTRLEN); return buf; } static unsigned int sockaddr_to_port(const struct sockaddr_storage *addr) { unsigned int rc; if (addr->ss_family == AF_INET) rc = ntohs(((struct sockaddr_in *)addr)->sin_port); else if (addr->ss_family == AF_INET6) rc = ntohs(((struct sockaddr_in6 *)addr)->sin6_port); else rc = -1; return rc; } static char *sockaddr_to_addr(struct sockaddr_storage *addr) { static char buf[64]; snprintf(buf, sizeof(buf), "%52s:%u", sockaddr_to_string(addr), sockaddr_to_port(addr)); return buf; } static void set_close_on_exec(int fd) { int flags = fcntl(fd, F_GETFD); if (flags == -1) flags = 0; flags |= FD_CLOEXEC; fcntl(fd, F_SETFD, flags); } static void release_client(struct ev_tcp *client) { char emsg[DEFAULT_BUF_SZ]; snprintf(emsg, sizeof(emsg), "addr=%s port=%u res=success", sockaddr_to_string(&client->addr), sockaddr_to_port(&client->addr)); send_audit_event(AUDIT_DAEMON_CLOSE, emsg); #ifdef USE_GSSAPI if (client->remote_name) free (client->remote_name); #endif shutdown(client->io.fd, SHUT_RDWR); close(client->io.fd); if (client_chain == client) client_chain = client->next; if (client->next) client->next->prev = client->prev; if (client->prev) client->prev->next = client->next; } static void close_client(struct ev_tcp *client) { release_client(client); free(client); } static int ar_write(int sock, const void *buf, int len) { int rc = 0, w; while (len > 0) { do { w = write(sock, buf, len); } while (w < 0 && errno == EINTR); if (w < 0) return w; if (w == 0) break; rc += w; len -= w; buf = (const void *)((const char *)buf + w); } return rc; } #ifdef USE_GSSAPI static int ar_read(int sock, void *buf, int len) { int rc = 0, r; while (len > 0) { do { r = read(sock, buf, len); } while (r < 0 && errno == EINTR); if (r < 0) return r; if (r == 0) break; rc += r; len -= r; buf = (void *)((char *)buf + r); } return rc; } /* Communications under GSS is done by token exchanges. Each "token" may contain a message, perhaps signed, perhaps encrypted. The messages within are what we're interested in, but the network sees the tokens. The protocol we use for transferring tokens is to send the length first, four bytes MSB first, then the token data. We return nonzero on error. */ static int recv_token(int s, gss_buffer_t tok) { int ret; unsigned char lenbuf[4]; unsigned int len; ret = ar_read(s, (char *)lenbuf, 4); if (ret < 0) { audit_msg(LOG_ERR, "GSS-API error reading token length"); return -1; } else if (!ret) { return 0; } else if (ret != 4) { audit_msg(LOG_ERR, "GSS-API error reading token length"); return -1; } len = ((lenbuf[0] << 24) | (lenbuf[1] << 16) | (lenbuf[2] << 8) | lenbuf[3]); if (len > MAX_AUDIT_MESSAGE_LENGTH) { audit_msg(LOG_ERR, "GSS-API error: event length exceeds MAX_AUDIT_LENGTH"); return -1; } tok->length = len; tok->value = (char *)malloc(tok->length ? tok->length : 1); if (tok->length && tok->value == NULL) { audit_msg(LOG_ERR, "Out of memory allocating token data"); return -1; } ret = ar_read(s, (char *)tok->value, tok->length); if (ret < 0) { audit_msg(LOG_ERR, "GSS-API error reading token data"); free(tok->value); return -1; } else if (ret != (int) tok->length) { audit_msg(LOG_ERR, "GSS-API error reading token data"); free(tok->value); return -1; } return 1; } /* Same here. */ static int send_token(int s, gss_buffer_t tok) { int ret; unsigned char lenbuf[4]; unsigned int len; if (tok->length > 0xffffffffUL) return -1; len = tok->length; lenbuf[0] = (len >> 24) & 0xff; lenbuf[1] = (len >> 16) & 0xff; lenbuf[2] = (len >> 8) & 0xff; lenbuf[3] = len & 0xff; ret = ar_write(s, (char *) lenbuf, 4); if (ret < 0) { audit_msg(LOG_ERR, "GSS-API error sending token length"); return -1; } else if (ret != 4) { audit_msg(LOG_ERR, "GSS-API error sending token length"); return -1; } ret = ar_write(s, tok->value, tok->length); if (ret < 0) { audit_msg(LOG_ERR, "GSS-API error sending token data"); return -1; } else if (ret != (int)tok->length) { audit_msg(LOG_ERR, "GSS-API error sending token data"); return -1; } return 0; } static void gss_failure_2(const char *msg, int status, int type) { OM_uint32 message_context = 0; OM_uint32 min_status = 0; gss_buffer_desc status_string; do { gss_display_status(&min_status, status, type, GSS_C_NO_OID, &message_context, &status_string); audit_msg (LOG_ERR, "GSS error: %s: %s", msg, (char *)status_string.value); gss_release_buffer(&min_status, &status_string); } while (message_context != 0); } static void gss_failure(const char *msg, int major_status, int minor_status) { gss_failure_2(msg, major_status, GSS_C_GSS_CODE); if (minor_status) gss_failure_2(msg, minor_status, GSS_C_MECH_CODE); } #define KCHECK(x,f, k) if (x) { \ const char *kstr = krb5_get_error_message(kcontext, x); \ audit_msg(LOG_ERR, "krb5 error: %s in %s\n", kstr, f); \ krb5_free_error_message(kcontext, kstr); \ krb5_free_context(k); k = NULL; \ return -1; } /* These are our private credentials, which come from a key file on our server. They are acquired once, at program start. */ static krb5_context kcontext = NULL; static int server_acquire_creds(const char *service_name, gss_cred_id_t *lserver_creds) { gss_buffer_desc name_buf; gss_name_t server_name; OM_uint32 major_status, minor_status; int krberr; my_service_name = strdup(service_name); name_buf.value = (char *)service_name; name_buf.length = strlen(name_buf.value) + 1; major_status = gss_import_name(&minor_status, &name_buf, (gss_OID) gss_nt_service_name, &server_name); if (major_status != GSS_S_COMPLETE) { gss_failure("importing name", major_status, minor_status); return -1; } major_status = gss_acquire_cred(&minor_status, server_name, GSS_C_INDEFINITE, GSS_C_NULL_OID_SET, GSS_C_ACCEPT, lserver_creds, NULL, NULL); if (major_status != GSS_S_COMPLETE) { gss_failure("acquiring credentials", major_status, minor_status); (void) gss_release_name(&minor_status, &server_name); return -1; } (void) gss_release_name(&minor_status, &server_name); krberr = krb5_init_context(&kcontext); KCHECK (krberr, "krb5_init_context", kcontext); krberr = krb5_get_default_realm(kcontext, &my_gss_realm); KCHECK (krberr, "krb5_get_default_realm", kcontext); audit_msg(LOG_DEBUG, "GSS creds for %s acquired", service_name); return 0; } /* This is where we negotiate a security context with the client. In the case of Kerberos, this is where the key exchange happens. FIXME: While everything else is strictly nonblocking, this negotiation blocks. */ static int negotiate_credentials(ev_tcp *io) { gss_buffer_desc send_tok, recv_tok; gss_name_t client; OM_uint32 maj_stat, min_stat, acc_sec_min_stat; gss_ctx_id_t *context; OM_uint32 sess_flags; char *slashptr, *atptr; context = & io->gss_context; *context = GSS_C_NO_CONTEXT; io->remote_name = NULL; maj_stat = GSS_S_CONTINUE_NEEDED; do { /* STEP 1 - get a token from the client. */ if (recv_token(io->io.fd, &recv_tok) <= 0) { audit_msg(LOG_ERR, "TCP session from %s will be closed, error ignored", sockaddr_to_addr(&io->addr)); return -1; } if (recv_tok.length == 0) { free(recv_tok.value); recv_tok.value = NULL; continue; } /* STEP 2 - let GSS process that token. */ maj_stat = gss_accept_sec_context(&acc_sec_min_stat, context, server_creds, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client, NULL, &send_tok, &sess_flags, NULL, NULL); if (recv_tok.value) gss_release_buffer(&min_stat, &recv_tok); if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) { gss_release_buffer(&min_stat, &send_tok); if (*context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); gss_failure("accepting context", maj_stat, acc_sec_min_stat); return -1; } /* STEP 3 - send any tokens to the client that GSS may ask us to send. */ if (send_tok.length != 0) { if (send_token(io->io.fd, &send_tok) < 0) { gss_release_buffer(&min_stat, &send_tok); audit_msg(LOG_ERR, "TCP session from %s will be closed, error ignored", sockaddr_to_addr(&io->addr)); if (*context != GSS_C_NO_CONTEXT) gss_delete_sec_context(&min_stat, context, GSS_C_NO_BUFFER); gss_release_name(&min_stat, &client); return -1; } } gss_release_buffer(&min_stat, &send_tok); } while (maj_stat == GSS_S_CONTINUE_NEEDED); maj_stat = gss_display_name(&min_stat, client, &recv_tok, NULL); gss_release_name(&min_stat, &client); if (maj_stat != GSS_S_COMPLETE) { gss_failure("displaying name", maj_stat, min_stat); return -1; } if (asprintf(&io->remote_name, "%.*s", (int)recv_tok.length, (char *)recv_tok.value) < 0) { io->remote_name = strdup("?"); io->remote_name_len = 1; } else io->remote_name_len = recv_tok.length; audit_msg(LOG_INFO, "GSS-API Accepted connection from: %s", io->remote_name); gss_release_buffer(&min_stat, &recv_tok); if (io->remote_name) { slashptr = strchr(io->remote_name, '/'); atptr = strchr(io->remote_name, '@'); } else slashptr = NULL; if (!slashptr || !atptr) { audit_msg(LOG_ERR, "Invalid GSS name from remote client: %s", io->remote_name); return -1; } *slashptr = 0; if (strcmp(io->remote_name, my_service_name)) { audit_msg(LOG_ERR, "Unauthorized GSS client name: %s (not %s)", io->remote_name, my_service_name); return -1; } *slashptr = '/'; if (strcmp(atptr+1, my_gss_realm)) { audit_msg(LOG_ERR, "Unauthorized GSS client realm: %s (not %s)", atptr+1, my_gss_realm); return -1; } return 0; } #endif /* USE_GSSAPI */ /* This is called from auditd-event after the message has been logged. The header is already filled in. */ static void client_ack(void *ack_data, const unsigned char *header, const char *msg) { ev_tcp *io = (ev_tcp *)ack_data; #ifdef USE_GSSAPI if (USE_GSS) { OM_uint32 major_status, minor_status; gss_buffer_desc utok, etok; int mlen; mlen = strlen(msg); utok.length = AUDIT_RMW_HEADER_SIZE + mlen; utok.value = malloc(utok.length + 1); memcpy(utok.value, header, AUDIT_RMW_HEADER_SIZE); memcpy(utok.value+AUDIT_RMW_HEADER_SIZE, msg, mlen); /* Wrapping the message creates a token for the client. Then we just have to worry about sending the token. */ major_status = gss_wrap(&minor_status, io->gss_context, 1, GSS_C_QOP_DEFAULT, &utok, NULL, &etok); if (major_status != GSS_S_COMPLETE) { gss_failure("encrypting message", major_status, minor_status); free(utok.value); return; } // FIXME: Should we check the return code of this? send_token(io->io.fd, &etok); free(utok.value); (void) gss_release_buffer(&minor_status, &etok); return; } #endif // Send the header and a text error message if it exists ar_write(io->io.fd, header, AUDIT_RMW_HEADER_SIZE); if (msg[0]) ar_write(io->io.fd, msg, strlen(msg)); } extern void distribute_event(struct auditd_event *e); static void client_message (struct ev_tcp *io, unsigned int length, unsigned char *header) { unsigned char ch; uint32_t type, mlen, seq; int hver, mver; if (AUDIT_RMW_IS_MAGIC (header, length)) { AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, mlen, seq) ch = header[length]; header[length] = 0; if (length > 1 && header[length-1] == '\n') header[length-1] = 0; if (type == AUDIT_RMW_TYPE_HEARTBEAT) { unsigned char ack[AUDIT_RMW_HEADER_SIZE]; AUDIT_RMW_PACK_HEADER (ack, 0, AUDIT_RMW_TYPE_ACK, 0, seq); client_ack(io, ack, ""); } else { struct auditd_event *e = create_event( header+AUDIT_RMW_HEADER_SIZE, client_ack, io, seq); if (e) distribute_event(e); } header[length] = ch; } } static void auditd_tcp_client_handler(struct ev_loop *loop, struct ev_io *_io, int revents) { struct ev_tcp *io = (struct ev_tcp *)_io; int i, r; int total_this_call = 0; io->client_active = 1; /* The socket is non-blocking, but we have a limited buffer size. In the event that we get a packet that's bigger than our buffer, we need to read it in multiple parts. Thus, we keep reading/parsing/processing until we run out of ready data. */ read_more: r = read (io->io.fd, io->buffer + io->bufptr, MAX_AUDIT_MESSAGE_LENGTH - io->bufptr); if (r < 0 && errno == EAGAIN) r = 0; /* We need to keep track of the difference between "no data * because it's closed" and "no data because we've read it * all". */ if (r == 0 && total_this_call > 0) { return; } /* If the connection is gracefully closed, the first read we try will return zero. If the connection times out or otherwise fails, the read will return -1. */ if (r <= 0) { if (r < 0) audit_msg(LOG_WARNING, "client %s socket closed unexpectedly", sockaddr_to_addr(&io->addr)); /* There may have been a final message without a LF. */ if (io->bufptr) { client_message(io, io->bufptr, io->buffer); } ev_io_stop(loop, _io); close_client(io); return; } total_this_call += r; more_messages: #ifdef USE_GSSAPI /* If we're using GSS at all, everything will be encrypted, one record per token. */ if (USE_GSS) { gss_buffer_desc utok, etok; io->bufptr += r; uint32_t len; OM_uint32 major_status, minor_status; /* We need at least four bytes to test the length. If we have more than four bytes, we can tell if we have a whole token (or more). */ if (io->bufptr < 4) return; len = ( ((uint32_t)(io->buffer[0] & 0xFF) << 24) | ((uint32_t)(io->buffer[1] & 0xFF) << 16) | ((uint32_t)(io->buffer[2] & 0xFF) << 8) | (uint32_t)(io->buffer[3] & 0xFF)); /* Make sure we got something big enough and not too big */ if (io->bufptr < 4 + len || len > MAX_AUDIT_MESSAGE_LENGTH) return; i = len + 4; etok.length = len; etok.value = io->buffer + 4; /* Unwrapping the token gives us the original message, which we know is already a single record. */ major_status = gss_unwrap(&minor_status, io->gss_context, &etok, &utok, NULL, NULL); if (major_status != GSS_S_COMPLETE) { gss_failure("decrypting message", major_status, minor_status); } else { /* client_message() wants to NUL terminate it, so copy it to a bigger buffer. Plus, we want to add our own tag. */ memcpy(msgbuf, utok.value, utok.length); while (utok.length > 0 && msgbuf[utok.length-1] == '\n') utok.length --; snprintf(msgbuf + utok.length, MAX_AUDIT_MESSAGE_LENGTH - utok.length, " krb5=%s", io->remote_name); utok.length += 6 + io->remote_name_len; client_message (io, utok.length, msgbuf); gss_release_buffer(&minor_status, &utok); } } else #endif if (AUDIT_RMW_IS_MAGIC (io->buffer, (io->bufptr+r))) { uint32_t type, len, seq; int hver, mver; unsigned char *header = (unsigned char *)io->buffer; io->bufptr += r; if (io->bufptr < AUDIT_RMW_HEADER_SIZE) return; AUDIT_RMW_UNPACK_HEADER (header, hver, mver, type, len, seq); /* Make sure len is not too big */ if (len > MAX_AUDIT_MESSAGE_LENGTH) return; i = len; i += AUDIT_RMW_HEADER_SIZE; /* See if we have enough bytes to extract the whole message. */ if (io->bufptr < i) return; /* We have an I-byte message in buffer. Send ACK */ client_message(io, i, io->buffer); } else { /* At this point, the buffer has IO->BUFPTR+R bytes in it. The first IO->BUFPTR bytes do not have a LF in them (we've already checked), we must check the R new bytes. */ for (i = io->bufptr; i < io->bufptr + r; i ++) if (io->buffer [i] == '\n') break; io->bufptr += r; /* Check for a partial message, with no LF yet. */ if (i == io->bufptr) return; i++; /* We have an I-byte message in buffer. Send ACK */ client_message(io, i, io->buffer); } /* Now copy any remaining bytes to the beginning of the buffer. */ memmove(io->buffer, io->buffer + i, io->bufptr - i); io->bufptr -= i; /* See if this packet had more than one message in it. */ if (io->bufptr > 0) { r = io->bufptr; io->bufptr = 0; goto more_messages; } /* Go back and see if there's more data to read. */ goto read_more; } #ifdef HAVE_LIBWRAP int allow_severity = LOG_INFO, deny_severity = LOG_NOTICE; static int auditd_tcpd_check(int sock) { struct request_info request; request_init(&request, RQ_DAEMON, "auditd", RQ_FILE, sock, 0); fromhost(&request); if (!hosts_access(&request)) return 1; return 0; } #endif /* * This function counts the number of concurrent connections and returns * a 1 if there are too many and a 0 otherwise. It assumes the incoming * connection has not been added to the linked list yet. */ static int check_num_connections(const struct sockaddr_storage *aaddr) { int num = 0; struct ev_tcp *client = client_chain; while (client) { int rc; struct sockaddr_storage *cl_addr = &client->addr; if (aaddr->ss_family == AF_INET) rc = memcmp(&((struct sockaddr_in *)aaddr)->sin_addr, &((struct sockaddr_in *)cl_addr)->sin_addr, sizeof(struct in_addr)); else rc = memcmp(&((struct sockaddr_in6 *)aaddr)->sin6_addr, &((struct sockaddr_in6 *)cl_addr)->sin6_addr, sizeof(struct in6_addr)); if (rc == 0) { num++; if (num >= max_per_addr) return 1; } client = client->next; } return 0; } void write_connection_state(FILE *f) { unsigned int num = 0, act = 0; struct ev_tcp *client = client_chain; fprintf(f, "listening for network connections = %s\n", nlsocks ? "yes" : "no"); if (nlsocks) { while (client) { if (client->client_active) act++; num++; client = client->next; } fprintf(f, "active connections = %u\n", act); fprintf(f, "total connections = %u\n", num); } } static void auditd_tcp_listen_handler( struct ev_loop *loop, struct ev_io *_io, int revents) { int one=1; int afd; socklen_t aaddrlen; struct sockaddr_storage aaddr; struct ev_tcp *client; char emsg[DEFAULT_BUF_SZ]; /* Accept the connection and see where it's coming from. */ aaddrlen = sizeof(aaddr); afd = accept(_io->fd, (struct sockaddr *)&aaddr, &aaddrlen); if (afd == -1) { audit_msg(LOG_ERR, "Unable to accept TCP connection"); return; } #ifdef HAVE_LIBWRAP if (use_libwrap) { if (auditd_tcpd_check(afd)) { shutdown(afd, SHUT_RDWR); close(afd); audit_msg(LOG_ERR, "TCP connection from %s rejected", sockaddr_to_addr(&aaddr)); snprintf(emsg, sizeof(emsg), "op=wrap addr=%s port=%u res=no", sockaddr_to_string(&aaddr), sockaddr_to_port(&aaddr)); send_audit_event(AUDIT_DAEMON_ACCEPT, emsg); return; } } #endif /* Verify it's coming from an authorized port. We assume the firewall * will block attempts from unauthorized machines. */ if (min_port > sockaddr_to_port(&aaddr) || sockaddr_to_port(&aaddr) > max_port) { audit_msg(LOG_ERR, "TCP connection from %s rejected", sockaddr_to_addr(&aaddr)); snprintf(emsg, sizeof(emsg), "op=port addr=%s port=%u res=no", sockaddr_to_string(&aaddr), sockaddr_to_port(&aaddr)); send_audit_event(AUDIT_DAEMON_ACCEPT, emsg); shutdown(afd, SHUT_RDWR); close(afd); return; } /* Make sure we don't have too many connections */ if (check_num_connections(&aaddr)) { audit_msg(LOG_ERR, "Too many connections from %s - rejected", sockaddr_to_addr(&aaddr)); snprintf(emsg, sizeof(emsg), "op=dup addr=%s port=%u res=no", sockaddr_to_string(&aaddr), sockaddr_to_port(&aaddr)); send_audit_event(AUDIT_DAEMON_ACCEPT, emsg); shutdown(afd, SHUT_RDWR); close(afd); return; } /* Connection is accepted...start setting it up */ setsockopt(afd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int)); setsockopt(afd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (int)); setsockopt(afd, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof (int)); set_close_on_exec(afd); /* Make the client data structure */ client = (struct ev_tcp *)malloc (sizeof (struct ev_tcp)); if (client == NULL) { audit_msg(LOG_CRIT, "Unable to allocate TCP client data"); snprintf(emsg, sizeof(emsg), "op=alloc addr=%s port=%u res=no", sockaddr_to_string(&aaddr), sockaddr_to_port(&aaddr)); send_audit_event(AUDIT_DAEMON_ACCEPT, emsg); shutdown(afd, SHUT_RDWR); close(afd); return; } memset(client, 0, sizeof (struct ev_tcp)); client->client_active = 1; // Was watching for EV_ERROR, but libev 3.48 took it away ev_io_init(&(client->io), auditd_tcp_client_handler, afd, EV_READ); memcpy(&client->addr, &aaddr, sizeof (struct sockaddr_storage)); #ifdef USE_GSSAPI if (USE_GSS && negotiate_credentials (client)) { shutdown(afd, SHUT_RDWR); close(afd); free(client->remote_name); free(client); return; } #endif fcntl(afd, F_SETFL, O_NONBLOCK | O_NDELAY); ev_io_start(loop, &(client->io)); /* Add the new connection to a linked list of active clients. */ client->next = client_chain; if (client->next) client->next->prev = client; client_chain = client; /* And finally log that we accepted the connection */ snprintf(emsg, sizeof(emsg), "addr=%s port=%u res=success", sockaddr_to_string(&aaddr), sockaddr_to_port(&aaddr)); send_audit_event(AUDIT_DAEMON_ACCEPT, emsg); } static void auditd_set_ports(unsigned minp, unsigned maxp, unsigned max_p_addr) { min_port = minp; max_port = maxp; max_per_addr = max_p_addr; } static void periodic_handler(struct ev_loop *loop, struct ev_periodic *per, int revents) { struct daemon_conf *config = (struct daemon_conf *) per->data; struct ev_tcp *ev, *next = NULL; int active; if (!config->tcp_client_max_idle) return; for (ev = client_chain; ev; ev = next) { next = ev->next; active = ev->client_active; ev->client_active = 0; if (active) continue; audit_msg(LOG_NOTICE, "client %s idle too long - closing connection\n", sockaddr_to_addr(&(ev->addr))); ev_io_stop(loop, &ev->io); release_client(ev); free(ev); } } int auditd_tcp_listen_init(struct ev_loop *loop, struct daemon_conf *config) { struct addrinfo *ai, *runp; struct addrinfo hints; char local[16]; int one = 1, rc; int prefer_ipv6 = 0; /* If the port is not set, that means we aren't going to listen for connections. */ if (config->tcp_listen_port == 0) return 0; memset(&hints, '\0', sizeof(hints)); hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; snprintf(local, sizeof(local), "%u", (unsigned)config->tcp_listen_port); rc = getaddrinfo(NULL, local, &hints, &ai); if (rc) { audit_msg(LOG_ERR, "Cannot lookup addresses"); return 1; } { int ipv4 = 0, ipv6 = 0; nlsocks = 0; runp = ai; while (runp && nlsocks < N_SOCKS) { // Let's take a pass through and see what we got. if (runp->ai_family == AF_INET) ipv4++; else if (runp->ai_family == AF_INET6) ipv6++; runp = runp->ai_next; nlsocks++; } if (nlsocks == 2 && ipv4 && ipv6) prefer_ipv6 = 1; } nlsocks = 0; runp = ai; while (runp && nlsocks < N_SOCKS) { // On linux, ipv6 sockets by default include ipv4 so // we only need one. if (runp->ai_family == AF_INET && prefer_ipv6) goto next_try; listen_socket[nlsocks] = socket(runp->ai_family, runp->ai_socktype, runp->ai_protocol); if (listen_socket[nlsocks] < 0) { audit_msg(LOG_ERR, "Cannot create %s listener socket", runp->ai_family == AF_INET ? "IPv4" : "IPv6"); goto next_try; } /* This avoids problems if auditd needs to be restarted. */ setsockopt(listen_socket[nlsocks], SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof (int)); // If we had more than 2 addresses suggested we'll // separate the sockets. if (!prefer_ipv6 && runp->ai_family == AF_INET6) setsockopt(listen_socket[nlsocks], IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); set_close_on_exec(listen_socket[nlsocks]); if (bind(listen_socket[nlsocks], runp->ai_addr, runp->ai_addrlen)) { if (errno != EADDRINUSE) audit_msg(LOG_ERR, "Cannot bind listener socket to port %ld (%s)", config->tcp_listen_port, strerror(errno)); close(listen_socket[nlsocks]); listen_socket[nlsocks] = -1; goto non_fatal; } if (listen(listen_socket[nlsocks], config->tcp_listen_queue)) { audit_msg(LOG_ERR, "Unable to listen on %ld (%s)", config->tcp_listen_port, strerror(errno)); close(listen_socket[nlsocks]); listen_socket[nlsocks] = -1; goto next_try; } struct protoent *p = getprotobynumber(runp->ai_protocol); audit_msg(LOG_DEBUG, "Listening on TCP port %ld, protocol %s", config->tcp_listen_port, p ? p->p_name: "?"); endprotoent(); ev_io_init(&tcp_listen_watcher, auditd_tcp_listen_handler, listen_socket[nlsocks], EV_READ); ev_io_start(loop, &tcp_listen_watcher); non_fatal: nlsocks++; if (nlsocks == N_SOCKS) break; next_try: runp = runp->ai_next; } freeaddrinfo(ai); if (nlsocks == 0) return -1; // Now that we have sockets, start the periodic timers transport = config->transport; ev_periodic_init(&periodic_watcher, periodic_handler, 0, config->tcp_client_max_idle, NULL); periodic_watcher.data = config; if (config->tcp_client_max_idle) ev_periodic_start(loop, &periodic_watcher); use_libwrap = config->use_libwrap; auditd_set_ports(config->tcp_client_min_port, config->tcp_client_max_port, config->tcp_max_per_addr); #ifdef USE_GSSAPI if (USE_GSS) { const char *princ = config->krb5_principal; const char *key_file; struct stat st; if (!princ) princ = "auditd"; /* This may fail, but we don't care. */ unsetenv ("KRB5_KTNAME"); if (config->krb5_key_file) key_file = config->krb5_key_file; else key_file = "/etc/audit/audit.key"; setenv ("KRB5_KTNAME", key_file, 1); if (stat(key_file, &st) == 0) { if ((st.st_mode & 07777) != 0400) { audit_msg (LOG_ERR, "%s is not mode 0400 (it's %#o) - compromised key?", key_file, st.st_mode & 07777); return -1; } if (st.st_uid != 0) { audit_msg(LOG_ERR, "%s is not owned by root (it's %d) - compromised key?", key_file, st.st_uid); return -1; } } if (server_acquire_creds(princ, &server_creds)) { free(my_service_name); my_service_name = NULL; return -1; } } #endif return 0; } void auditd_tcp_listen_uninit(struct ev_loop *loop, struct daemon_conf *config) { #ifdef USE_GSSAPI OM_uint32 status; #endif /* If the port isn't set, we didn't listen for connections. */ if (config->tcp_listen_port == 0) return; ev_io_stop(loop, &tcp_listen_watcher); while (nlsocks > 0) { nlsocks--; close(listen_socket[nlsocks]); } #ifdef USE_GSSAPI if (USE_GSS) { gss_release_cred(&status, &server_creds); krb5_free_context(kcontext); kcontext = NULL; free(my_service_name); my_service_name = NULL; } #endif while (client_chain) { unsigned char ack[AUDIT_RMW_HEADER_SIZE]; AUDIT_RMW_PACK_HEADER (ack, 0, AUDIT_RMW_TYPE_ENDING, 0, 0); client_ack(client_chain, ack, ""); ev_io_stop(loop, &client_chain->io); close_client(client_chain); } if (config->tcp_client_max_idle) ev_periodic_stop(loop, &periodic_watcher); transport = T_TCP; } static void periodic_reconfigure(const struct daemon_conf *config) { struct ev_loop *loop = ev_default_loop(EVFLAG_AUTO); if (config->tcp_listen_port && config->tcp_client_max_idle) { ev_periodic_set(&periodic_watcher, ev_now(loop), config->tcp_client_max_idle, NULL); ev_periodic_start(loop, &periodic_watcher); } else { ev_periodic_stop(loop, &periodic_watcher); } } void auditd_tcp_listen_reconfigure(const struct daemon_conf *nconf, struct daemon_conf *oconf) { use_libwrap = nconf->use_libwrap; /* Look at network things that do not need restarting */ if (oconf->tcp_client_min_port != nconf->tcp_client_min_port || oconf->tcp_client_max_port != nconf->tcp_client_max_port || oconf->tcp_max_per_addr != nconf->tcp_max_per_addr) { oconf->tcp_client_min_port = nconf->tcp_client_min_port; oconf->tcp_client_max_port = nconf->tcp_client_max_port; oconf->tcp_max_per_addr = nconf->tcp_max_per_addr; auditd_set_ports(oconf->tcp_client_min_port, oconf->tcp_client_max_port, oconf->tcp_max_per_addr); } if (oconf->tcp_client_max_idle != nconf->tcp_client_max_idle) { oconf->tcp_client_max_idle = nconf->tcp_client_max_idle; periodic_reconfigure(oconf); } if (oconf->tcp_listen_port != nconf->tcp_listen_port || oconf->tcp_listen_queue != nconf->tcp_listen_queue) { oconf->tcp_listen_port = nconf->tcp_listen_port; oconf->tcp_listen_queue = nconf->tcp_listen_queue; // FIXME: need to restart the network stuff } free((void *)oconf->krb5_principal); // Copying the config for now. Should compare if the same // and recredential if needed. oconf->krb5_principal = nconf->krb5_principal; } audit-userspace-4.0.5/src/auditd-listen.h000066400000000000000000000033001501761310600203200ustar00rootroot00000000000000/* auditd-config.h -- * Copyright 2004-2007 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * DJ Delorie * */ #ifndef AUDITD_LISTEN_H #define AUDITD_LISTEN_H #include "config.h" #include "ev.h" #include #ifdef USE_LISTENER int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config ); void auditd_tcp_listen_uninit ( struct ev_loop *loop, struct daemon_conf *config ); void auditd_tcp_listen_reconfigure ( const struct daemon_conf *nconf, struct daemon_conf *oconf ); void write_connection_state(FILE *f); #else static inline int auditd_tcp_listen_init ( struct ev_loop *loop, struct daemon_conf *config ) { return 0; } static inline void auditd_tcp_listen_uninit ( struct ev_loop *loop, struct daemon_conf *config ) { return; } static inline void auditd_tcp_listen_reconfigure ( struct daemon_conf *nconf, struct daemon_conf *oconf ) { return; } #endif /* USE_LISTENER */ #endif audit-userspace-4.0.5/src/auditd-reconfig.c000066400000000000000000000070041501761310600206160ustar00rootroot00000000000000/* auditd-reconfig.c -- * Copyright 2005,2021 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include #include #include #include #include #include "libaudit.h" #include "auditd-event.h" #include "auditd-config.h" #include "private.h" /* externs we need to know about */ extern void reconfig_ready(void); /* This is the configuration manager code */ static pthread_t config_thread; static pthread_mutex_t config_lock; // Only let one run at a time static void *config_thread_main(void *arg); void init_config_manager(void) { pthread_mutex_init(&config_lock, NULL); audit_msg(LOG_DEBUG, "config_manager init complete"); } int start_config_manager(struct auditd_event *e) { int retval, rc = 0; retval = pthread_mutex_trylock(&config_lock); if (retval == 0) { pthread_attr_t detached; pthread_attr_init(&detached); pthread_attr_setdetachstate(&detached, PTHREAD_CREATE_DETACHED); if (pthread_create(&config_thread, &detached, config_thread_main, e) > 0) { audit_msg(LOG_ERR, "Couldn't create config thread, no config changes"); free(e); pthread_mutex_unlock(&config_lock); rc = 1; } pthread_attr_destroy(&detached); } else { audit_msg(LOG_ERR, "Config thread already running, no config changes"); free(e); rc = 1; } return rc; } static void *config_thread_main(void *arg) { sigset_t sigs; struct auditd_event *e = (struct auditd_event *)arg; struct daemon_conf new_config; extern int send_audit_event(int type, const char *str); /* This is a worker thread. Don't handle signals. */ sigemptyset(&sigs); sigaddset(&sigs, SIGTERM); sigaddset(&sigs, SIGHUP); sigaddset(&sigs, SIGUSR1); sigaddset(&sigs, SIGUSR2); sigaddset(&sigs, SIGCHLD); sigaddset(&sigs, SIGCONT); pthread_sigmask(SIG_SETMASK, &sigs, NULL); if (load_config(&new_config, TEST_AUDITD) == 0) { /* We will re-use the current reply */ new_config.sender_uid = e->reply.signal_info->uid; new_config.sender_pid = e->reply.signal_info->pid; if (e->reply.len > 24) new_config.sender_ctx = strdup(e->reply.signal_info->ctx); else new_config.sender_ctx = strdup("?"); memcpy(e->reply.msg.data, &new_config, sizeof(new_config)); e->reply.conf = (struct daemon_conf *)e->reply.msg.data; e->reply.type = AUDIT_DAEMON_RECONFIG; reconfig_ready(); } else { // need to send a failed event message char txt[MAX_AUDIT_MESSAGE_LENGTH]; audit_format_signal_info(txt, sizeof(txt), "reconfigure state=no-change", &e->reply, "failed"); // FIXME: need to figure out sending this //send_audit_event(AUDIT_DAEMON_CONFIG, txt); free_config(&new_config); free(e); } pthread_mutex_unlock(&config_lock); return NULL; } audit-userspace-4.0.5/src/auditd-sendmail.c000066400000000000000000000056221501761310600206220ustar00rootroot00000000000000/* auditd-sendmail.c -- * Copyright 2005 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #include "config.h" #include #include // for access() #include #include #include #include "libaudit.h" #include "private.h" #include "auditd-config.h" extern const char *email_command; static int safe_popen(pid_t *pid, const char *mail_acct); // returns 1 on error & 0 if OK int sendmail(const char *subject, const char *content, const char *mail_acct) { pid_t pid; if (access(email_command, 01) == 0) { FILE *mail; int fd; fd = safe_popen(&pid, mail_acct); if (fd < 0) return 1; mail = fdopen(fd, "w"); if (mail == NULL) { kill(pid, SIGKILL); close(fd); audit_msg(LOG_ERR, "Error - starting mail"); return 1; } fprintf(mail, "To: %s\n", mail_acct); fprintf(mail, "From: root\n"); // fprintf(mail, "X-Sender: %s\n", mail_acct); fprintf(mail, "Subject: %s\n\n", subject); // End of Header fprintf(mail, "%s\n", content); fprintf(mail, ".\n\n"); // Close it up... fclose(mail); return 0; } else audit_msg(LOG_ERR, "Error - %s isn't executable", email_command); return 1; } static int safe_popen(pid_t *pid, const char *mail_acct) { char *argv[4]; char acct[256]; int pipe_fd[2]; struct sigaction sa; if (pipe(pipe_fd)) { audit_msg(LOG_ALERT, "Audit daemon failed to create pipe while sending email alert"); return -1; } *pid = fork(); if (*pid < 0) { close(pipe_fd[0]); close(pipe_fd[1]); audit_msg(LOG_ALERT, "Audit daemon failed to fork while sending email alert"); return -1; } if (*pid) { /* Parent */ close(pipe_fd[0]); // adjust pipe return pipe_fd[1]; } /* Child */ sigfillset (&sa.sa_mask); sigprocmask (SIG_UNBLOCK, &sa.sa_mask, 0); close(pipe_fd[1]); // adjust pipe dup2(pipe_fd[0], 0); /* Make email acct param */ snprintf(acct, sizeof(acct), "-f%s", mail_acct); /* Stuff arg list */ argv[0] = (char *)email_command; argv[1] = (char *)"-t"; argv[2] = acct; argv[3] = NULL; execve(email_command, argv, NULL); audit_msg(LOG_ALERT, "Audit daemon failed to exec %s", email_command); exit(1); } audit-userspace-4.0.5/src/auditd.c000066400000000000000000000714021501761310600170270ustar00rootroot00000000000000/* auditd.c -- * Copyright 2004-09,2011,2013,2016-18,2021 Red Hat Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Rickard E. (Rik) Faith */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_MALLINFO2 #include #endif #include "libaudit.h" #include "auditd-event.h" #include "auditd-config.h" #include "auditd-dispatch.h" #include "auditd-listen.h" #include "common.h" #include "libdisp.h" #include "private.h" #include "ev.h" #if EV_CHILD_ENABLE #error "LIBEV must not have EV_CHILD_ENABLE set" #endif #define EV_STOP() do {\ ev_unloop(ev_default_loop(EVFLAG_AUTO), EVUNLOOP_ALL);\ AUDIT_ATOMIC_STORE(stop, 1);\ } while (0) #define DEFAULT_BUF_SZ 448 #define DMSG_SIZE (DEFAULT_BUF_SZ + 48) #define SUCCESS 0 #define FAILURE 1 #define SUBJ_LEN 4097 /* Global Data */ #ifdef HAVE_ATOMIC ATOMIC_INT stop = 0; #else volatile ATOMIC_INT stop = 0; #endif /* Local data */ static int fd = -1, pipefds[2] = {-1, -1}; static struct daemon_conf config; static const char *pidfile = "/var/run/auditd.pid"; static const char *state_file = "/var/run/auditd.state"; static int init_pipe[2]; static int do_fork = 1, opt_aggregate_only = 0, config_dir_set = 0; static struct auditd_event *cur_event = NULL, *reconfig_ev = NULL; static ATOMIC_INT hup_info_requested = 0; static ATOMIC_INT usr1_info_requested = 0, usr2_info_requested = 0; static char subj[SUBJ_LEN]; static uint32_t session; static struct ev_timer report_timer_watcher; struct ev_loop *loop; /* Local function prototypes */ int send_audit_event(int type, const char *str); static void clean_exit(void); static int get_reply(int fd, struct audit_reply *rep, int seq); static char *getsubj(char *subj); enum startup_state {startup_disable=0, startup_enable, startup_nochange, startup_INVALID}; static const char *startup_states[] = {"disable", "enable", "nochange"}; /* * Output a usage message */ static void usage(void) { fprintf(stderr, "Usage: auditd [-f] [-l] [-n] [-s %s|%s|%s] " "[-c ]\n", startup_states[startup_disable], startup_states[startup_enable], startup_states[startup_nochange]); exit(2); } /* * SIGTERM handler */ static void term_handler(struct ev_loop *loop, struct ev_signal *sig, int revents) { EV_STOP (); } /* * Used to reconfigure the daemon */ static void hup_handler( struct ev_loop *loop, struct ev_signal *sig, int revents ) { int rc; rc = audit_request_signal_info(fd); if (rc < 0) send_audit_event(AUDIT_DAEMON_CONFIG, "op=reconfigure state=no-change auid=-1 pid=-1 subj=? res=failed"); else hup_info_requested = 1; } /* * Used to force log rotation */ static void user1_handler(struct ev_loop *loop, struct ev_signal *sig, int revents) { int rc; rc = audit_request_signal_info(fd); if (rc < 0) send_audit_event(AUDIT_DAEMON_ROTATE, "op=rotate-logs auid=-1 pid=-1 subj=? res=failed"); else usr1_info_requested = 1; } /* * Used to resume logging */ static void user2_handler( struct ev_loop *loop, struct ev_signal *sig, int revents ) { int rc; rc = audit_request_signal_info(fd); if (rc < 0) { resume_logging(); send_audit_event(AUDIT_DAEMON_RESUME, "op=resume-logging auid=-1 pid=-1 subj=? res=success"); } else usr2_info_requested = 1; } /* * Used with email alerts to cleanup */ static void child_handler(struct ev_loop *loop, struct ev_signal *sig, int revents) { int pid; while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { if (pid == dispatcher_pid()) dispatcher_reaped(); } } static void child_handler2( int sig ) { child_handler(NULL, NULL, 0); } #ifdef HAVE_MALLINFO2 static struct mallinfo2 last_mi; static void write_memory_state(FILE *f) { struct mallinfo2 mi = mallinfo2(); fprintf(f, "glibc arena (total memory) is: %zu KB, was: %zu KB\n", (size_t)mi.arena/1024, (size_t)last_mi.arena/1024); fprintf(f, "glibc uordblks (in use memory) is: %zu KB, was: %zu KB\n", (size_t)mi.uordblks/1024,(size_t)last_mi.uordblks/1024); fprintf(f,"glibc fordblks (total free space) is: %zu KB, was: %zu KB\n", (size_t)mi.fordblks/1024,(size_t)last_mi.fordblks/1024); memcpy(&last_mi, &mi, sizeof(struct mallinfo2)); } #endif /* * Used to dump internal state information */ static void cont_handler(struct ev_loop *loop, struct ev_signal *sig, int revents) { char buf[64]; mode_t u = umask(0137); // allow 0640 FILE *f = fopen(state_file, "w"); umask(u); if (f == NULL) return; int sr_fd = fileno(f); if (sr_fd > 0) (void)fchown(sr_fd, 0, config.log_group); fprintf(f, "audit version = %s\n", VERSION); time_t now = time(0); strftime(buf, sizeof(buf), "%x %X", localtime(&now)); fprintf(f, "current time = %s\n", buf); fprintf(f, "process priority = %d\n", getpriority(PRIO_PROCESS, 0)); write_logging_state(f); libdisp_write_queue_state(f); #ifdef USE_LISTENER write_connection_state(f); #endif #ifdef HAVE_MALLINFO2 write_memory_state(f); #endif fclose(f); } static void report_timer_cb(struct ev_loop *loop __attribute__((unused)), struct ev_timer *w __attribute__((unused)), int revents __attribute__((unused))) { raise(SIGCONT); } void update_report_timer(unsigned int interval) { if (!loop) return; if (interval == 0) ev_timer_stop(loop, &report_timer_watcher); else { ev_timer_stop(loop, &report_timer_watcher); ev_timer_set(&report_timer_watcher, interval, interval); ev_timer_start(loop, &report_timer_watcher); } } static int extract_type(const char *str) { char tmp, *ptr2, *ptr = (char *)str; int type; if (*str == 'n') { ptr = strchr(str+1, ' '); if (ptr == NULL) return -1; // Malformed - bomb out ptr++; } // ptr should be at 't' ptr2 = strchr(ptr, ' '); if (ptr2 == NULL) return -1; // Malformed - bomb out // find = str = strchr(ptr, '='); if (str == NULL || str >= ptr2) return -1; // Malformed - bomb out // name is 1 past str++; // Save character & terminate string tmp = *ptr2; *ptr2 = 0; type = audit_name_to_msg_type(str); *ptr2 = tmp; // Restore character return type; } void distribute_event(struct auditd_event *e) { int route = 1, proto; if (config.log_format == LF_ENRICHED) proto = AUDISP_PROTOCOL_VER2; else proto = AUDISP_PROTOCOL_VER; /* If type is 0, then its a network originating event */ if (e->reply.type == 0) { // See if we are distributing network originating events if (!dispatch_network_events()) route = 0; else { // We only need the original type if its being routed e->reply.type = extract_type(e->reply.message); // Treat everything from the network as VER2 // because they are already formatted. This is // important when it gets to the dispatcher which // can strip node= when its VER1. proto = AUDISP_PROTOCOL_VER2; } } else if (e->reply.type != AUDIT_DAEMON_RECONFIG) { // All other local events need formatting format_event(e); // If the event has been formatted with node, upgrade // to VER2 so that the dispatcher honors the formatting if (config.node_name_format != N_NONE) proto = AUDISP_PROTOCOL_VER2; } else route = 0; // Don't DAEMON_RECONFIG events until after enqueue /* End of Event is for realtime interface - skip local logging of it */ if (e->reply.type != AUDIT_EOE) handle_event(e); /* Write to local disk */ /* Next, send to plugins */ if (route) dispatch_event(&e->reply, proto); /* Free msg and event memory */ cleanup_event(e); } /* * This function is used to send start, stop, and abort messages * to the audit log. */ static unsigned seq_num = 0; int send_audit_event(int type, const char *str) { struct auditd_event *e; struct timeval tv; e = create_event(NULL, 0, NULL, 0); if (e == NULL) { audit_msg(LOG_ERR, "Cannot allocate audit reply"); return 1; } e->reply.type = type; if (seq_num == 0) { // seq_num does not have to cryptographically secure srandom(time(NULL)); seq_num = random()%10000; } else seq_num++; // Write event into netlink area like normal events if (gettimeofday(&tv, NULL) == 0) { e->reply.len = snprintf((char *)e->reply.msg.data, DMSG_SIZE, "audit(%lld.%03u:%u): %s", (long long int)tv.tv_sec, (unsigned)(tv.tv_usec/1000), seq_num, str); } else { e->reply.len = snprintf((char *)e->reply.msg.data, DMSG_SIZE, "audit(%lld.%03d:%u): %s", (long long int)time(NULL), 0, seq_num, str); } // Point message at the netlink buffer like normal events e->reply.message = e->reply.msg.data; if (e->reply.len > DMSG_SIZE) e->reply.len = DMSG_SIZE; distribute_event(e); return 0; } static int write_pid_file(void) { int pidfd, len; char val[16]; len = snprintf(val, sizeof(val), "%u\n", getpid()); if (len <= 0) { audit_msg(LOG_ERR, "Pid error (%s)", strerror(errno)); pidfile = 0; return 1; } pidfd = open(pidfile, O_CREAT | O_TRUNC | O_NOFOLLOW | O_WRONLY, 0644); if (pidfd < 0) { audit_msg(LOG_ERR, "Unable to set pidfile (%s)", strerror(errno)); pidfile = 0; return 1; } if (write(pidfd, val, (unsigned int)len) != len) { audit_msg(LOG_ERR, "Unable to write pidfile (%s)", strerror(errno)); close(pidfd); pidfile = 0; return 1; } close(pidfd); return 0; } static void avoid_oom_killer(void) { int oomfd, len, rc; char *score = NULL; /* New kernels use different technique */ if ((oomfd = open("/proc/self/oom_score_adj", O_NOFOLLOW | O_WRONLY)) >= 0) { score = "-1000"; } else if ((oomfd = open("/proc/self/oom_adj", O_NOFOLLOW | O_WRONLY)) >= 0) { score = "-17"; } else { audit_msg(LOG_NOTICE, "Cannot open out of memory adjuster"); return; } len = strlen(score); rc = write(oomfd, score, len); if (rc != len) audit_msg(LOG_NOTICE, "Unable to adjust out of memory score"); close(oomfd); } /* * This function will take care of becoming a daemon. The parent * will wait until the child notifies it by writing into a special * pipe to signify that it successfully initialized. This prevents * a race in the init script where rules get loaded before the daemon * is ready and they wind up in syslog. The child returns 0 on success * and nonzero on failure. The parent returns nonzero on failure. On * success, the parent calls _exit with 0. */ static int become_daemon(void) { int nfd, rc; pid_t pid; int status; if (do_fork) { if (pipe(init_pipe) || fcntl(init_pipe[0], F_SETFD, FD_CLOEXEC) || fcntl(init_pipe[1], F_SETFD, FD_CLOEXEC)) return -1; pid = fork(); } else pid = 0; switch (pid) { case 0: /* No longer need this... */ if (do_fork) close(init_pipe[0]); /* Open stdin,out,err to /dev/null */ nfd = open("/dev/null", O_RDWR); if (nfd < 0) { audit_msg(LOG_ERR, "Cannot open /dev/null"); return -1; } if ((dup2(nfd, 0) < 0) || (dup2(nfd, 1) < 0) || (dup2(nfd, 2) < 0)) { audit_msg(LOG_ERR, "Cannot reassign descriptors to /dev/null"); close(nfd); return -1; } close(nfd); /* Change to '/' */ rc = chdir("/"); if (rc < 0) { audit_msg(LOG_ERR, "Cannot change working directory to /"); return -1; } /* Become session/process group leader */ setsid(); break; case -1: return -1; default: /* Wait for the child to say its done */ do { rc = read(init_pipe[0], &status,sizeof(status)); } while (rc < 0 && errno == EINTR); if (rc < 0) return -1; /* Success - die a happy death */ if (status == SUCCESS) { free_config(&config); _exit(0); } return -1; } return 0; } static void tell_parent(int status) { ssize_t rc; if (config.daemonize != D_BACKGROUND || do_fork == 0) return; do { rc = write(init_pipe[1], &status, sizeof(status)); } while (rc < 0 && errno == EINTR); } static void netlink_handler(struct ev_loop *loop, struct ev_io *io, int revents) { int rc = 1, cnt = 0; // Try to get all the events that are waiting but yield after 5 to // let other handlers run. Five should cover PATH events. // FIXME: backing down to 3 until IPC is faster while (rc > 0 && cnt < 3) { if (cur_event == NULL) { if ((cur_event = malloc(sizeof(*cur_event))) == NULL) { char emsg[DEFAULT_BUF_SZ]; if (*subj) snprintf(emsg, sizeof(emsg), "op=error-halt auid=%u pid=%d subj=%s res=failed", audit_getloginuid(), getpid(), subj); else snprintf(emsg, sizeof(emsg), "op=error-halt auid=%u pid=%d res=failed", audit_getloginuid(), getpid()); EV_STOP (); send_audit_event(AUDIT_DAEMON_ABORT, emsg); audit_msg(LOG_ERR, "Cannot allocate audit reply, exiting"); shutdown_events(); if (pidfile) unlink(pidfile); shutdown_dispatcher(); return; } cur_event->ack_func = NULL; } rc = audit_get_reply(fd, &cur_event->reply, GET_REPLY_NONBLOCKING, 0); if (rc > 0) { switch (cur_event->reply.type) { /* Don't process these */ case NLMSG_NOOP: case NLMSG_DONE: case NLMSG_ERROR: case AUDIT_GET: /* Or these */ case AUDIT_WATCH_INS...AUDIT_WATCH_LIST: case AUDIT_ADD_RULE...AUDIT_GET_FEATURE: case AUDIT_FIRST_DAEMON...AUDIT_LAST_DAEMON: case AUDIT_REPLACE: break; case AUDIT_SIGNAL_INFO: if (hup_info_requested) { char hup[MAX_AUDIT_MESSAGE_LENGTH]; audit_msg(LOG_DEBUG, "HUP detected, starting config manager"); reconfig_ev = cur_event; if (start_config_manager(cur_event)) { audit_format_signal_info(hup, sizeof(hup), "reconfigure state=no-change", &cur_event->reply, "failed"); send_audit_event(AUDIT_DAEMON_CONFIG, hup); } cur_event = NULL; hup_info_requested = 0; } else if (usr1_info_requested) { char usr1[MAX_AUDIT_MESSAGE_LENGTH]; audit_format_signal_info(usr1, sizeof(usr1), "rotate-logs", &cur_event->reply, "success"); send_audit_event(AUDIT_DAEMON_ROTATE, usr1); usr1_info_requested = 0; } else if (usr2_info_requested) { char usr2[MAX_AUDIT_MESSAGE_LENGTH]; audit_format_signal_info(usr2, sizeof(usr2), "resume-logging", &cur_event->reply, "success"); resume_logging(); libdisp_resume(); send_audit_event(AUDIT_DAEMON_RESUME, usr2); usr2_info_requested = 0; } break; default: distribute_event(cur_event); cur_event = NULL; break; } } cnt++; } } static void pipe_handler(struct ev_loop *loop, struct ev_io *io, int revents) { char buf[16]; // Drain the pipe - won't block because libev sets non-blocking mode if (read(pipefds[0], buf, sizeof(buf)) < 0) ; /* Intentionally blank - nothing we can do */ enqueue_event(reconfig_ev); reconfig_ev = NULL; } void reconfig_ready(void) { const char *msg = "ready\n"; if (write(pipefds[1], msg, strlen(msg)) < 0) ; /* Intentionally empty - nothing we can do */ } static void close_pipes(void) { close(pipefds[0]); close(pipefds[1]); } int main(int argc, char *argv[]) { struct sigaction sa; struct rlimit limit; int i, c, rc; static const struct option opts[] = { {"foreground", no_argument, NULL, 'f'}, {"allow_links", no_argument, NULL, 'l'}, {"disable_fork", no_argument, NULL, 'n'}, {"enable_state", required_argument, NULL, 's'}, {"config_file", required_argument, NULL, 'c'}, {NULL, 0, NULL, 0} }; int opt_foreground = 0, opt_allow_links = 0; enum startup_state opt_startup = startup_enable; extern char *optarg; extern int optind; struct ev_io netlink_watcher; struct ev_io pipe_watcher; struct ev_signal sigterm_watcher; struct ev_signal sighup_watcher; struct ev_signal sigusr1_watcher; struct ev_signal sigusr2_watcher; struct ev_signal sigchld_watcher; struct ev_signal sigcont_watcher; /* Get params && set mode */ while ((c = getopt_long(argc, argv, "flns:c:", opts, NULL)) != -1) { switch (c) { case 'f': opt_foreground = 1; break; case 'l': opt_allow_links = 1; break; case 'n': do_fork = 0; break; case 's': for (i=0; i 0) { struct audit_reply trep; rc = get_reply(fd, &trep, rc); if (rc > 0) { char txt[MAX_AUDIT_MESSAGE_LENGTH]; audit_format_signal_info(txt, sizeof(txt), "terminate", &trep, "success"); send_audit_event(AUDIT_DAEMON_END, txt); } } if (rc <= 0) send_audit_event(AUDIT_DAEMON_END, "op=terminate auid=-1 uid=-1 ses=-1 pid=-1 subj=? res=success"); free(cur_event); // Tear down IO watchers Part 2 if (!opt_aggregate_only) ev_io_stop (loop, &netlink_watcher); ev_io_stop (loop, &pipe_watcher); close_pipes(); // Give DAEMON_END event a little time to be sent in case // of remote logging usleep(10000); // 10 milliseconds libdisp_shutdown(); usleep(20000); // 20 milliseconds // Tear down IO watchers Part 3 ev_signal_stop(loop, &sigchld_watcher); shutdown_events(); free_config(&config); ev_default_destroy(); return 0; } /* * A clean exit means : * 1) we log that we are going down * 2) deregister with kernel * 3) close the netlink socket */ static void clean_exit(void) { audit_msg(LOG_INFO, "The audit daemon is exiting."); if (fd >= 0) { if (!opt_aggregate_only) if (audit_set_pid(fd, 0, WAIT_NO)) ; // intentionally empty audit_close(fd); } if (pidfile) unlink(pidfile); unlink(state_file); closelog(); } /* * This function is used to get the reply for term info. * Returns 1 on success & -1 on failure. */ static int get_reply(int rfd, struct audit_reply *rep, int seq) { int rc, i; int timeout = 30; /* tenths of seconds */ for (i = 0; i < timeout; i++) { struct timeval t; fd_set read_mask; t.tv_sec = 0; t.tv_usec = 100000; /* .1 second */ FD_ZERO(&read_mask); FD_SET(rfd, &read_mask); do { rc = select(rfd+1, &read_mask, NULL, NULL, &t); } while (rc < 0 && errno == EINTR); rc = audit_get_reply(rfd, rep, GET_REPLY_NONBLOCKING, 0); if (rc > 0) { /* Don't make decisions based on wrong packet */ if (rep->nlh->nlmsg_seq != seq) continue; /* If its not what we are expecting, keep looping */ if (rep->type == AUDIT_SIGNAL_INFO) return 1; /* If we get done or error, break out */ if (rep->type == NLMSG_DONE || rep->type == NLMSG_ERROR) break; } } return -1; } // Get the subj label of the daemon static char *getsubj(char *dsubj) { pid_t pid = getpid(); char filename[48]; ssize_t num_read; int sfd; snprintf(filename, sizeof(filename), "/proc/%u/attr/current", pid); sfd = open(filename, O_RDONLY); if(sfd == -1) { dsubj[0] = 0; return NULL; } do { num_read = read(sfd, dsubj, SUBJ_LEN-1); } while (num_read < 0 && errno == EINTR); close(sfd); if(num_read <= 0) { dsubj[0] = 0; return NULL; } dsubj[num_read] = '\0'; return dsubj; } audit-userspace-4.0.5/src/aureport-options.c000066400000000000000000000447051501761310600211150ustar00rootroot00000000000000/* aureport-options.c - parse commandline options and configure aureport * Copyright 2005-08,2010-11,2014,2018 Red Hat Inc., Durham, North Carolina. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Marcelo Henrique Cerri */ #include "config.h" #include #include #include #include #include #include #include #include #include #include "aureport-options.h" #include "ausearch-time.h" #include "libaudit.h" #include "auparse-defs.h" /* Global vars that will be accessed by the main program */ char *user_file = NULL; int force_logs = 0; int no_config = 0; /* These are for compatibility with parser */ unsigned int event_id = -1; uid_t event_uid = -1, event_loginuid = -2, event_euid = -1; const char *event_tuid = NULL, *event_teuid = NULL, *event_tauid = NULL; gid_t event_gid = -1, event_egid = -1; slist *event_node_list = NULL; const char *event_key = NULL; const char *event_filename = NULL; const char *event_exe = NULL; const char *event_comm = NULL; const char *event_hostname = NULL; const char *event_terminal = NULL; const char *event_subject = NULL; const char *event_object = NULL; const char *event_uuid = NULL; const char *event_vmname = NULL; long long event_exit = 0; int event_exit_is_set = 0; pid_t event_ppid = -1; uint32_t event_session_id = -2; int event_debug = 0, event_machine = -1; time_t arg_eoe_timeout = (time_t)0; /* These are used by aureport */ const char *dummy = "dummy"; report_type_t report_type = RPT_UNSET; report_det_t report_detail = D_UNSET; report_t report_format = RPT_DEFAULT; failed_t event_failed = F_BOTH; conf_act_t event_conf_act = C_NEITHER; success_t event_success = S_SUCCESS; int event_pid = 0; auparse_esc_t escape_mode = AUPARSE_ESC_TTY; struct nv_pair { int value; const char *name; }; enum { R_INFILE, R_TIME_END, R_TIME_START, R_VERSION, R_LOG_TIMES, R_CONFIGS, R_LOGINS, R_USERS, R_TERMINALS, R_HOSTS, R_EXES, R_FILES, R_AVCS, R_SYSCALLS, R_PIDS, R_EVENTS, R_ACCT_MODS, R_INTERPRET, R_HELP, R_ANOMALY, R_RESPONSE, R_SUMMARY_DET, R_CRYPTO, R_MAC, R_FAILED, R_SUCCESS, R_ADD, R_DEL, R_AUTH, R_NODE, R_IN_LOGS, R_KEYS, R_TTY, R_NO_CONFIG, R_COMM, R_VIRT, R_INTEG, R_ESCAPE, R_DEBUG, R_EOE_TMO }; static const struct nv_pair optiontab[] = { { R_AUTH, "-au" }, { R_AUTH, "--auth" }, { R_AVCS, "-a" }, { R_AVCS, "--avc" }, { R_ADD, "--add" }, { R_CONFIGS, "-c" }, { R_COMM, "--comm" }, { R_CONFIGS, "--config" }, { R_CRYPTO, "-cr" }, { R_CRYPTO, "--crypto" }, { R_DEBUG, "--debug" }, { R_DEL, "--delete" }, { R_EVENTS, "-e" }, { R_EVENTS, "--event" }, { R_ESCAPE, "--escape" }, { R_EOE_TMO, "--eoe-timeout" }, { R_FILES, "-f" }, { R_FILES, "--file" }, { R_FAILED, "--failed" }, { R_HOSTS, "-h" }, { R_HOSTS, "--host" }, { R_HELP, "--help" }, { R_INTERPRET, "-i" }, { R_INTERPRET, "--interpret" }, { R_INFILE, "-if" }, { R_INFILE, "--input" }, { R_IN_LOGS, "--input-logs" }, { R_INTEG, "--integrity" }, { R_KEYS, "-k" }, { R_KEYS, "--key" }, { R_LOGINS, "-l" }, { R_LOGINS, "--login" }, { R_ACCT_MODS, "-m" }, { R_ACCT_MODS, "--mods" }, { R_MAC, "-ma" }, { R_MAC, "--mac" }, { R_NODE, "--node" }, { R_NO_CONFIG, "-nc" }, { R_NO_CONFIG, "--no-config" }, { R_ANOMALY, "-n" }, { R_ANOMALY, "--anomaly" }, { R_PIDS, "-p" }, { R_PIDS, "--pid" }, { R_RESPONSE, "-r" }, { R_RESPONSE, "--response" }, { R_SYSCALLS, "-s" }, { R_SYSCALLS, "--syscall" }, { R_SUCCESS, "--success" }, { R_SUMMARY_DET, "--summary" }, { R_LOG_TIMES, "-t" }, { R_LOG_TIMES, "--log" }, { R_TIME_END, "-te"}, { R_TIME_END, "--end"}, { R_TERMINALS, "-tm"}, // don't like this { R_TERMINALS, "--terminal"}, // don't like this { R_TIME_START, "-ts" }, { R_TTY, "--tty" }, { R_TIME_START, "--start" }, { R_USERS, "-u" }, { R_USERS, "--user" }, { R_VERSION, "-v" }, { R_VERSION, "--version" }, { R_EXES, "-x" }, { R_EXES, "--executable" }, { R_VIRT, "--virt" } }; #define OPTION_NAMES (sizeof(optiontab)/sizeof(optiontab[0])) static int audit_lookup_option(const char *name) { unsigned int i; for (i = 0; i < OPTION_NAMES; i++) if (!strcmp(optiontab[i].name, name)) return optiontab[i].value; return -1; } static void usage(void) { printf("usage: aureport [options]\n" "\t-a,--avc\t\t\tAvc report\n" "\t-au,--auth\t\t\tAuthentication report\n" "\t--comm\t\t\t\tCommands run report\n" "\t-c,--config\t\t\tConfig change report\n" "\t-cr,--crypto\t\t\tCrypto report\n" "\t--debug\t\t\t\tWrite malformed events that are skipped to stderr\n" "\t--eoe-timeout secs\t\tEnd of Event Timeout\n" "\t-e,--event\t\t\tEvent report\n" "\t--escape option\t\t\tEscape output\n" "\t-f,--file\t\t\tFile name report\n" "\t--failed\t\t\tonly failed events in report\n" "\t-h,--host\t\t\tRemote Host name report\n" "\t--help\t\t\t\thelp\n" "\t-i,--interpret\t\t\tInterpretive mode\n" "\t-if,--input \tuse this file as input\n" "\t--input-logs\t\t\tUse the logs even if stdin is a pipe\n" "\t--integrity\t\t\tIntegrity event report\n" "\t-k,--key\t\t\tKey report\n" "\t-l,--login\t\t\tLogin report\n" "\t-m,--mods\t\t\tModification to accounts report\n" "\t-ma,--mac\t\t\tMandatory Access Control (MAC) report\n" "\t-n,--anomaly\t\t\taNomaly report\n" "\t-nc,--no-config\t\t\tDon't include config events\n" "\t--node \t\tOnly events from a specific node\n" "\t-p,--pid\t\t\tPid report\n" "\t-r,--response\t\t\tResponse to anomaly report\n" "\t-s,--syscall\t\t\tSyscall report\n" "\t--success\t\t\tonly success events in report\n" "\t--summary\t\t\tsorted totals for main object in report\n" "\t-t,--log\t\t\tLog time range report\n" "\t-te,--end [end date] [end time]\tending date & time for reports\n" "\t-tm,--terminal\t\t\tTerMinal name report\n" "\t-ts,--start [start date] [start time]\tstarting data & time for reports\n" "\t--tty\t\t\t\tReport about tty keystrokes\n" "\t-u,--user\t\t\tUser name report\n" "\t-v,--version\t\t\tVersion\n" "\t--virt\t\t\t\tVirtualization report\n" "\t-x,--executable\t\t\teXecutable name report\n" "\tIf no report is given, the summary report will be displayed\n" ); } static int set_report(report_type_t r) { if (report_type == RPT_UNSET) { report_type = r; return 0; } else { fprintf(stderr, "Error - only one report can be specified"); return 1; } } static int set_detail(report_det_t d) { if (report_detail == D_UNSET) { report_detail = d; return 0; } else if (d == D_SUM) { report_detail = d; return 0; } else { return 1; } } /* * This function examines the commandline parameters and sets various * search options. It returns a 0 on success and < 0 on failure */ int check_params(int count, char *vars[]) { int c = 1; int retval = 0; const char *optarg; while (c < count && retval == 0) { // Go ahead and point to the next argument if (c+1 < count) { if (vars[c+1][0] != '-') optarg = vars[c+1]; else optarg = NULL; } else optarg = NULL; switch (audit_lookup_option(vars[c])) { case R_INFILE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { if (strlen(optarg) >= PATH_MAX-32) { fprintf(stderr, "File name is too long %s\n", optarg); retval = -1; break; } user_file = strdup(optarg); if (user_file == NULL) retval = -1; c++; } break; case R_LOG_TIMES: if (set_report(RPT_TIME)) retval = -1; else set_detail(D_DETAILED); break; case R_AVCS: if (set_report(RPT_AVC)) retval = -1; else { set_detail(D_DETAILED); event_comm = dummy; event_subject = dummy; event_object = dummy; } break; case R_AUTH: if (set_report(RPT_AUTH)) retval = -1; else { set_detail(D_DETAILED); event_exe = dummy; event_hostname = dummy; event_terminal = dummy; event_uid = 1; } break; case R_MAC: if (set_report(RPT_MAC)) retval = -1; else { set_detail(D_DETAILED); event_loginuid = 1; event_tauid = dummy; } break; case R_INTEG: if (set_report(RPT_INTEG)) retval = -1; else { set_detail(D_DETAILED); event_loginuid = 1; event_tauid = dummy; } break; case R_VIRT: if (set_report(RPT_VIRT)) retval = -1; else { set_detail(D_DETAILED); } break; case R_CONFIGS: if (set_report(RPT_CONFIG)) retval = -1; else { set_detail(D_DETAILED); event_loginuid = 1; event_tauid = dummy; } break; case R_CRYPTO: if (set_report(RPT_CRYPTO)) retval = -1; else { set_detail(D_DETAILED); event_loginuid = 1; event_tauid = dummy; } break; case R_LOGINS: if (set_report(RPT_LOGIN)) retval = -1; else { set_detail(D_DETAILED); event_exe = dummy; event_hostname = dummy; event_terminal = dummy; event_loginuid = 1; event_tauid = dummy; } break; case R_ACCT_MODS: if (set_report(RPT_ACCT_MOD)) retval = -1; else { set_detail(D_DETAILED); event_exe = dummy; event_hostname = dummy; event_terminal = dummy; event_loginuid = 1; event_tauid = dummy; } break; case R_EVENTS: if (set_report(RPT_EVENT)) retval = -1; else { // if (!optarg) { set_detail(D_DETAILED); event_loginuid = 1; event_tauid = dummy; // } else { // UNIMPLEMENTED; // set_detail(D_SPECIFIC); // if (isdigit((unsigned char)optarg[0])) { // errno = 0; // event_id = strtoul(optarg, // NULL, 10); // if (errno) { // fprintf(stderr, // "Illegal value for audit event ID"); // retval = -1; // } // c++; // } else { // fprintf(stderr, // "Audit event id must be a numeric value, was %s\n", // optarg); // retval = -1; // } // } } break; case R_FILES: if (set_report(RPT_FILE)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_filename = dummy; event_exe = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_HOSTS: if (set_report(RPT_HOST)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_hostname = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_INTERPRET: report_format = RPT_INTERP; if (optarg) { fprintf(stderr, "Argument is NOT required for %s\n", vars[c]); retval = -1; } break; case R_PIDS: if (set_report(RPT_PID)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_exe = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_SYSCALLS: if (set_report(RPT_SYSCALL)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_comm = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_TERMINALS: if (set_report(RPT_TERM)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_terminal = dummy; event_hostname = dummy; event_exe = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_USERS: if (set_report(RPT_USER)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_terminal = dummy; event_hostname = dummy; event_exe = dummy; event_uid = 1; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_EXES: if (set_report(RPT_EXE)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_terminal = dummy; event_hostname = dummy; event_exe = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_COMM: if (set_report(RPT_COMM)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_terminal = dummy; event_hostname = dummy; event_comm = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_ANOMALY: if (set_report(RPT_ANOMALY)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_terminal = dummy; event_hostname = dummy; event_exe = dummy; event_comm = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_RESPONSE: if (set_report(RPT_RESPONSE)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); } else { UNIMPLEMENTED; } } break; case R_KEYS: if (set_report(RPT_KEY)) retval = -1; else { if (!optarg) { set_detail(D_DETAILED); event_exe = dummy; event_key = dummy; event_loginuid = 1; event_tauid = dummy; } else { UNIMPLEMENTED; } } break; case R_TTY: if (set_report(RPT_TTY)) retval = -1; else { set_detail(D_DETAILED); event_session_id = 1; event_loginuid = 1; event_tauid = dummy; event_terminal = dummy; event_comm = dummy; } break; case R_TIME_END: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order*/ if (strchr(optarg, ':')) { if (ausearch_time_end(vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_end(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_end(optarg, "00:00:00") != 0) retval = -1; } else if ( (strchr(optarg, ':')) == NULL) { /* Only have date */ if (ausearch_time_end(optarg, NULL) != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_end(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case R_TIME_START: if (optarg) { if ( (c+2 < count) && vars[c+2] && (vars[c+2][0] != '-') ) { /* Have both date and time - check order */ if (strchr(optarg, ':')) { if (ausearch_time_start( vars[c+2], optarg) != 0) retval = -1; } else { if (ausearch_time_start(optarg, vars[c+2]) != 0) retval = -1; } c++; } else { // Check against recognized words int t = lookup_time(optarg); if (t >= 0) { if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else if ( strchr(optarg, ':') == NULL) { /* Only have date */ if (ausearch_time_start(optarg, "00:00:00") != 0) retval = -1; } else { /* Only have time */ if (ausearch_time_start(NULL, optarg) != 0) retval = -1; } } c++; break; } fprintf(stderr, "%s requires either date and/or time\n", vars[c]); retval = -1; break; case R_NODE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { snode sn; c++; if (!event_node_list) { event_node_list = malloc(sizeof (slist)); if (!event_node_list) { retval = -1; break; } slist_create(event_node_list); } sn.str = strdup(optarg); sn.key = NULL; sn.hits=0; slist_append(event_node_list, &sn); } break; case R_ESCAPE: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; } else { if (strcmp(optarg, "raw") == 0) escape_mode = AUPARSE_ESC_RAW; else if (strcmp(optarg, "tty") == 0) escape_mode = AUPARSE_ESC_TTY; else if (strncmp(optarg, "shell", 6) == 0) escape_mode = AUPARSE_ESC_SHELL; else if (strcmp(optarg, "shell_quote") == 0) escape_mode = AUPARSE_ESC_SHELL_QUOTE; else { fprintf(stderr, "Unknown option (%s)\n", optarg); retval = -1; break; } c++; } break; case R_SUMMARY_DET: set_detail(D_SUM); break; case R_FAILED: event_failed = F_FAILED; break; case R_SUCCESS: event_failed = F_SUCCESS; break; case R_ADD: event_conf_act = C_ADD; break; case R_DEL: event_conf_act = C_DEL; break; case R_DEBUG: event_debug = 1; break; case R_IN_LOGS: force_logs = 1; break; case R_NO_CONFIG: no_config = 1; break; case R_VERSION: printf("aureport version %s\n", VERSION); exit(0); break; case R_HELP: usage(); exit(0); break; case R_EOE_TMO: if (!optarg) { fprintf(stderr, "Argument is required for %s\n", vars[c]); retval = -1; break; } if (isdigit((unsigned char)optarg[0])) { errno = 0; arg_eoe_timeout = (time_t)strtoul(optarg, NULL, 10); if (errno || arg_eoe_timeout == 0) { fprintf(stderr, "Illegal value for End of Event Timeout, was %s\n", optarg); retval = -1; } c++; } else { fprintf(stderr, "End of Event Timeout must be a numeric value, was %s\n", optarg); retval = -1; } break; default: fprintf(stderr, "%s is an unsupported option\n", vars[c]); retval = -1; break; } c++; } if (retval >= 0) { if (report_type == RPT_UNSET) { if (set_report(RPT_SUMMARY)) retval = -1; else { set_detail(D_SUM); event_filename = dummy; event_hostname = dummy; event_terminal = dummy; event_exe = dummy; event_comm = dummy; event_key = dummy; event_loginuid = 1; event_tauid = dummy; } } } else usage(); return retval; } audit-userspace-4.0.5/src/aureport-options.h000066400000000000000000000033561501761310600211170ustar00rootroot00000000000000/* aureport-options.h -- * Copyright 2005-06, 2008,2014 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef AUREPORT_OPTIONS_H #define AUREPORT_OPTIONS_H #include #include #include "ausearch-common.h" /* Global variables that describe what search is to be performed */ typedef enum { RPT_UNSET, RPT_TIME, RPT_SUMMARY, RPT_AVC, RPT_MAC, RPT_CONFIG, RPT_EVENT, RPT_FILE, RPT_HOST, RPT_LOGIN, RPT_ACCT_MOD, RPT_PID, RPT_SYSCALL, RPT_TERM, RPT_USER, RPT_EXE, RPT_ANOMALY, RPT_RESPONSE, RPT_CRYPTO, RPT_AUTH, RPT_KEY, RPT_TTY, RPT_COMM, RPT_VIRT, RPT_INTEG } report_type_t; typedef enum { D_UNSET, D_SUM, D_DETAILED, D_SPECIFIC } report_det_t; extern report_type_t report_type; extern report_det_t report_detail; extern report_t report_format; /* Function to process commandline options */ extern int check_params(int count, char *vars[]); #include #define UNIMPLEMENTED { fprintf(stderr,"Unimplemented option\n"); exit(1); } #endif audit-userspace-4.0.5/src/aureport-output.c000066400000000000000000000713341501761310600207600ustar00rootroot00000000000000/* * aureport-output.c - Print the report * Copyright (c) 2005-06,2008,2014,2017 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include "aureport-scan.h" #include "aureport-options.h" #include "ausearch-lookup.h" /* Locale functions */ static void print_title_summary(void); static void print_title_detailed(void); static void do_summary_output(void); static void do_file_summary_output(slist *sptr); static void do_string_summary_output(slist *sptr); static void do_user_summary_output(slist *sptr); static void do_int_summary_output(ilist *sptr); static void do_syscall_summary_output(slist *sptr); static void do_type_summary_output(ilist *sptr); /* Local Data */ static unsigned int line_item; void print_title(void) { line_item = 0U; printf("\n"); switch (report_detail) { case D_SUM: print_title_summary(); break; case D_DETAILED: print_title_detailed(); break; case D_SPECIFIC: default: break; } } static void print_title_summary(void) { if (event_failed == F_FAILED) printf("Failed "); if (event_failed == F_SUCCESS) printf("Success "); switch (report_type) { case RPT_SUMMARY: printf("Summary Report\n"); printf("======================\n"); break; case RPT_AVC: printf("Avc Object Summary Report\n"); printf("=================================\n"); printf("total obj\n"); printf("=================================\n"); break; case RPT_MAC: printf("MAC Summary Report\n"); printf("==================\n"); printf("total type\n"); printf("==================\n"); break; case RPT_INTEG: printf("Integrity Summary Report\n"); printf("========================\n"); printf("total type\n"); printf("========================\n"); break; case RPT_VIRT: printf("Virtualization Summary Report\n"); printf("=============================\n"); printf("total type\n"); printf("=============================\n"); break; case RPT_CONFIG: printf("Config Change Summary Report\n"); printf("============================\n"); printf("total type\n"); printf("============================\n"); break; case RPT_AUTH: printf("Authentication Summary Report\n"); printf("=============================\n"); printf("total acct\n"); printf("=============================\n"); break; case RPT_LOGIN: printf("Login Summary Report\n"); printf("============================\n"); printf("total auid\n"); printf("============================\n"); break; case RPT_ACCT_MOD: printf("Acct Modification Summary Report\n"); printf("================================\n"); printf("total type\n"); printf("================================\n"); break; case RPT_TIME: UNIMPLEMENTED; break; case RPT_EVENT: printf("Event Summary Report\n"); printf("======================\n"); printf("total type\n"); printf("======================\n"); break; case RPT_FILE: printf("File Summary Report\n"); printf("===========================\n"); printf("total file\n"); printf("===========================\n"); break; case RPT_HOST: printf("Host Summary Report\n"); printf("===========================\n"); printf("total host\n"); printf("===========================\n"); break; case RPT_PID: printf("Pid Summary Report\n"); printf("==========================\n"); printf("total pid\n"); printf("==========================\n"); break; case RPT_SYSCALL: printf("Syscall Summary Report\n"); printf("==========================\n"); printf("total syscall\n"); printf("==========================\n"); break; case RPT_TERM: printf("Terminal Summary Report\n"); printf("===============================\n"); printf("total terminal\n"); printf("===============================\n"); break; case RPT_USER: printf("User Summary Report\n"); printf("===========================\n"); printf("total auid\n"); printf("===========================\n"); break; case RPT_EXE: printf("Executable Summary Report\n"); printf("=================================\n"); printf("total file\n"); printf("=================================\n"); break; case RPT_COMM: printf("Command Summary Report\n"); printf("=================================\n"); printf("total command\n"); printf("=================================\n"); break; case RPT_ANOMALY: printf("Anomaly Summary Report\n"); printf("======================\n"); printf("total type\n"); printf("======================\n"); break; case RPT_RESPONSE: printf("Anomaly Response Summary Report\n"); printf("===============================\n"); printf("total type\n"); printf("===============================\n"); break; case RPT_CRYPTO: printf("Crypto Summary Report\n"); printf("=====================\n"); printf("total type\n"); printf("=====================\n"); break; case RPT_KEY: printf("Key Summary Report\n"); printf("===========================\n"); printf("total key\n"); printf("===========================\n"); break; case RPT_TTY: UNIMPLEMENTED; break; default: break; } } static void print_title_detailed(void) { switch (report_type) { case RPT_AVC: printf("AVC Report\n"); printf( "===============================================================\n"); printf( "# date time comm subj syscall class permission obj result event\n"); printf( "===============================================================\n"); break; case RPT_CONFIG: printf("Config Change Report\n"); printf("===================================\n"); printf("# date time type auid success event\n"); printf("===================================\n"); break; case RPT_AUTH: printf("Authentication Report\n"); printf( "============================================\n"); printf( "# date time acct host term exe success event\n"); printf( "============================================\n"); break; case RPT_LOGIN: printf("Login Report\n"); printf( "============================================\n"); printf( "# date time auid host term exe success event\n"); printf( "============================================\n"); break; case RPT_ACCT_MOD: printf("Account Modifications Report\n"); printf( "=================================================\n"); printf( "# date time auid addr term exe acct success event\n"); printf( "=================================================\n"); break; case RPT_TIME: printf("Log Time Range Report\n"); printf("=====================\n"); break; case RPT_EVENT: if (report_detail == D_DETAILED) { printf("Event Report\n"); printf("===================================\n"); printf("# date time event type auid success\n"); printf("===================================\n"); } else { printf("Specific Event Report\n"); printf("=====================\n"); } break; case RPT_FILE: if (report_detail == D_DETAILED) { printf("File Report\n"); printf( "===============================================\n"); printf( "# date time file syscall success exe auid event\n"); printf( "===============================================\n"); } else { printf("Specific File Report\n"); printf("====================\n"); } break; case RPT_HOST: if (report_detail == D_DETAILED) { printf("Host Report\n"); printf("===================================\n"); printf("# date time host syscall auid event\n"); printf("===================================\n"); } else { printf("Specific Host Report\n"); printf("====================\n"); } break; case RPT_PID: if (report_detail == D_DETAILED) { printf("Process ID Report\n"); printf( "======================================\n"); printf( "# date time pid exe syscall auid event\n"); printf( "======================================\n"); } else { printf("Specific Process ID Report\n"); printf("==========================\n"); } break; case RPT_SYSCALL: if (report_detail == D_DETAILED) { printf("Syscall Report\n"); printf( "=======================================\n"); printf( "# date time syscall pid comm auid event\n"); printf( "=======================================\n"); } else { printf("Specific Syscall Report\n"); printf("=======================\n"); } break; case RPT_TERM: if (report_detail == D_DETAILED) { printf("Terminal Report\n"); printf( "====================================\n"); printf( "# date time term host exe auid event\n"); printf( "====================================\n"); } else { printf("Specific Terminal Report\n"); printf("========================\n"); } break; case RPT_USER: if (report_detail == D_DETAILED) { printf("User ID Report\n"); printf( "====================================\n"); printf( "# date time auid term host exe event\n"); printf( "====================================\n"); } else { printf("Specific User ID Report\n"); printf("=======================\n"); } break; case RPT_EXE: if (report_detail == D_DETAILED) { printf("Executable Report\n"); printf( "====================================\n"); printf( "# date time exe term host auid event\n"); printf( "====================================\n"); } else { printf("Specific Executable Report\n"); printf("==========================\n"); } break; case RPT_COMM: if (report_detail == D_DETAILED) { printf("Command Report\n"); printf( "====================================\n"); printf( "# date time comm term host auid event\n"); printf( "=====================================\n"); } else { printf("Specific command Report\n"); printf("=======================\n"); } break; case RPT_ANOMALY: if (report_detail == D_DETAILED) { printf("Anomaly Report\n"); printf( "=========================================\n"); printf( "# date time type exe term host auid event\n"); printf( "=========================================\n"); } else { printf("Specific Anomaly Report\n"); printf("=======================\n"); } break; case RPT_RESPONSE: if (report_detail == D_DETAILED) { printf("Response to Anomaly Report\n"); printf("==============================\n"); printf("# date time type success event\n"); printf("==============================\n"); } else { printf("Specific Response to Anomaly Report\n"); printf("===================================\n"); } break; case RPT_MAC: if (report_detail == D_DETAILED) { printf("MAC Report\n"); printf("===================================\n"); printf("# date time auid type success event\n"); printf("===================================\n"); } else { printf("Specific Mandatory Access Control (MAC) Report\n"); printf("===================================\n"); } break; case RPT_INTEG: if (report_detail == D_DETAILED) { printf("Integrity Report\n"); printf("==============================\n"); printf("# date time type success event\n"); printf("==============================\n"); } else { printf("Specific Integrity Report\n"); printf("==============================\n"); } break; case RPT_VIRT: if (report_detail == D_DETAILED) { printf("Virtualization Report\n"); printf("==============================\n"); printf("# date time type success event\n"); printf("==============================\n"); } else { printf("Specific Virtualization Report\n"); printf("==============================\n"); } break; case RPT_CRYPTO: if (report_detail == D_DETAILED) { printf("Crypto Report\n"); printf("===================================\n"); printf("# date time auid type success event\n"); printf("===================================\n"); } else { printf("Specific Crypto Report\n"); printf("===================================\n"); } break; case RPT_KEY: if (report_detail == D_DETAILED) { printf("Key Report\n"); printf( "===============================================\n"); printf( "# date time key success exe auid event\n"); printf( "===============================================\n"); } else { printf("Specific Key Report\n"); printf("====================\n"); } break; case RPT_TTY: if (report_detail == D_DETAILED) { printf("TTY Report\n"); printf( "===============================================\n"); printf( "# date time event auid term sess comm data\n"); printf( "===============================================\n"); } else { printf("Specific TTY Report\n"); printf("====================\n"); } break; default: break; } } void print_per_event_item(llist *l) { char buf[128]; char name[64]; char date[32]; struct tm *tv; // The beginning is common to all reports tv = localtime(&l->e.sec); if (tv) strftime(date, sizeof(date), "%x %T", tv); else strcpy(date, "?"); if (report_type != RPT_AVC) { line_item++; printf("%u. %s ", line_item, date); } switch (report_type) { case RPT_AVC: alist_find_avc(l->s.avc); do { anode *an = l->s.avc->cur; line_item++; printf("%u. %s ", line_item, date); // command subject syscall action obj res event safe_print_string(l->s.comm ? l->s.comm : "?", 0); printf(" %s %s %s %s %s %s %lu\n", an->scontext, aulookup_syscall(l, buf,sizeof(buf)), an->avc_class, an->avc_perm, an->tcontext, aulookup_result(an->avc_result), l->e.serial); //printf("items:%d\n", l->s.avc->cnt); } while (alist_next_avc(l->s.avc)); break; case RPT_CONFIG: // FIXME:who, action, what, outcome, event // NOW: type auid success event printf("%s %s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_uid(l->s.loginuid, name, sizeof(name)), aulookup_success(l->s.success), l->e.serial); break; case RPT_AUTH: // who, addr, terminal, exe, success, event // Special note...uid is used here because that is // the way that the message works. This is because // on failed logins, loginuid is not set. safe_print_string(l->s.acct ? l->s.acct : aulookup_uid(l->s.uid, name, sizeof(name)), 0); printf(" %s %s %s %s %lu\n", l->s.hostname, l->s.terminal, l->s.exe, aulookup_success(l->s.success), l->e.serial); break; case RPT_LOGIN: // who, addr, terminal, exe, success, event // Special note...loginuid can be used here for // successful logins. loginuid is not set on failed // logins so acct is used in that situation. safe_print_string(((l->s.success == S_FAILED) && l->s.acct) ? l->s.acct : aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %s %s %lu\n", l->s.hostname, l->s.terminal, l->s.exe, aulookup_success(l->s.success), l->e.serial); break; case RPT_ACCT_MOD: // who, addr, terminal, exe, success, event safe_print_string( aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %s %s %s %lu\n", l->s.hostname ? l->s.hostname : "?", l->s.terminal ? l->s.terminal : "?", l->s.exe ? l->s.exe : "?", l->s.acct ? l->s.acct : "?", aulookup_success(l->s.success), l->e.serial); break; case RPT_EVENT: // report_detail == D_DETAILED // event, type, who, success printf("%lu %s ", l->e.serial, audit_msg_type_to_name(l->head->type)); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s\n", aulookup_success(l->s.success)); break; case RPT_FILE: // report_detail == D_DETAILED // file, syscall, success, exe, who, event { slist *s = l->s.filename; slist_first(s); if (s->cnt > 1) { char *key = s->cur ? s->cur->key : NULL; while (key && strcmp(key, "PARENT") == 0) { slist_next(s); key = s->cur ? s->cur->key : NULL; } } safe_print_string(s->cur ? s->cur->str : "", 0); printf(" %s %s ", aulookup_syscall(l,buf,sizeof(buf)), aulookup_success(l->s.success)); safe_print_string(l->s.exe ? l->s.exe : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); } break; case RPT_HOST: // report_detail == D_DETAILED // host, syscall, who, event printf("%s %s ", l->s.hostname, aulookup_syscall(l,buf,sizeof(buf))); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_PID: // report_detail == D_DETAILED // pid, exe, syscall, who, event printf("%u ", l->s.pid); safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %s ", aulookup_syscall(l,buf,sizeof(buf))); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_SYSCALL: // report_detail == D_DETAILED // syscall, pid, comm, who, event printf("%s %u ", aulookup_syscall(l,buf,sizeof(buf)), l->s.pid); safe_print_string(l->s.comm ? l->s.comm : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_TERM: // report_detail == D_DETAILED // terminal, host, exe, who, event printf("%s %s ", l->s.terminal, l->s.hostname); safe_print_string(l->s.exe, 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_USER: // report_detail == D_DETAILED // who, terminal, host, exe, event safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %lu\n", l->e.serial); break; case RPT_EXE: // report_detail == D_DETAILED // exe, terminal, host, who, event safe_print_string(l->s.exe ? l->s.exe : "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_COMM: // report_detail == D_DETAILED // comm, terminal, host, who, event safe_print_string(l->s.comm ? l->s.comm : "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_ANOMALY: // report_detail == D_DETAILED // type exe term host auid event printf("%s ", audit_msg_type_to_name(l->head->type)); safe_print_string(l->s.exe ? l->s.exe : l->s.comm ? l->s.comm: "?", 0); printf(" %s %s ", l->s.terminal ? l->s.terminal : "?", l->s.hostname ? l->s.hostname : "?"); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_RESPONSE: // report_detail == D_DETAILED // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_MAC: // auid type success event printf("%s %s %s %lu\n", aulookup_uid(l->s.loginuid, name, sizeof(name)), audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_INTEG: // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_VIRT: // type success event printf("%s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_CRYPTO: // auid type success event safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %s %lu\n", audit_msg_type_to_name(l->head->type), aulookup_success(l->s.success), l->e.serial); break; case RPT_KEY: // report_detail == D_DETAILED // key, success, exe, who, event slist_first(l->s.key); printf("%s %s ", l->s.key->cur->str, aulookup_success(l->s.success)); safe_print_string(l->s.exe ? l->s.exe : "?", 0); putchar(' '); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %lu\n", l->e.serial); break; case RPT_TTY: { char *ch, *ptr = strstr(l->head->message, "data="); if (!ptr) break; ptr += 5; ch = strrchr(ptr, ' '); if (ch) *ch = 0; // event who term sess data printf("%lu ", l->e.serial); safe_print_string(aulookup_uid(l->s.loginuid, name, sizeof(name)), 0); printf(" %s %u ", l->s.terminal ? l->s.terminal : "?", l->s.session_id); safe_print_string(l->s.comm ? l->s.comm: "?", 0); putchar(' '); print_tty_data(ptr); printf("\n"); } break; default: break; } } void print_wrap_up(void) { if (report_detail != D_SUM) return; switch (report_type) { case RPT_SUMMARY: do_summary_output(); break; case RPT_AVC: slist_sort_by_hits(&sd.avc_objs); do_string_summary_output(&sd.avc_objs); break; case RPT_CONFIG: /* We will borrow the pid list */ ilist_sort_by_hits(&sd.pids); do_type_summary_output(&sd.pids); break; case RPT_AUTH: slist_sort_by_hits(&sd.users); do_user_summary_output(&sd.users); break; case RPT_LOGIN: slist_sort_by_hits(&sd.users); do_user_summary_output(&sd.users); break; case RPT_ACCT_MOD: /* We will borrow the pid list */ ilist_sort_by_hits(&sd.pids); do_type_summary_output(&sd.pids); break; case RPT_EVENT: /* We will borrow the pid list */ ilist_sort_by_hits(&sd.pids); do_type_summary_output(&sd.pids); break; case RPT_FILE: slist_sort_by_hits(&sd.files); do_file_summary_output(&sd.files); break; case RPT_HOST: slist_sort_by_hits(&sd.hosts); do_string_summary_output(&sd.hosts); break; case RPT_PID: ilist_sort_by_hits(&sd.pids); do_int_summary_output(&sd.pids); break; case RPT_SYSCALL: slist_sort_by_hits(&sd.sys_list); do_syscall_summary_output(&sd.sys_list); break; case RPT_TERM: slist_sort_by_hits(&sd.terms); do_string_summary_output(&sd.terms); break; case RPT_USER: slist_sort_by_hits(&sd.users); do_user_summary_output(&sd.users); break; case RPT_EXE: slist_sort_by_hits(&sd.exes); do_file_summary_output(&sd.exes); break; case RPT_COMM: slist_sort_by_hits(&sd.comms); do_file_summary_output(&sd.comms); break; case RPT_ANOMALY: ilist_sort_by_hits(&sd.anom_list); do_type_summary_output(&sd.anom_list); break; case RPT_RESPONSE: ilist_sort_by_hits(&sd.resp_list); do_type_summary_output(&sd.resp_list); break; case RPT_MAC: ilist_sort_by_hits(&sd.mac_list); do_type_summary_output(&sd.mac_list); break; case RPT_INTEG: ilist_sort_by_hits(&sd.integ_list); do_type_summary_output(&sd.integ_list); break; case RPT_VIRT: ilist_sort_by_hits(&sd.virt_list); do_type_summary_output(&sd.virt_list); break; case RPT_CRYPTO: ilist_sort_by_hits(&sd.crypto_list); do_type_summary_output(&sd.crypto_list); break; case RPT_KEY: slist_sort_by_hits(&sd.keys); do_file_summary_output(&sd.keys); break; default: break; } } static void do_summary_output(void) { extern event very_first_event; extern event very_last_event; printf("Range of time in logs: "); { struct tm *btm; char tmp[48]; btm = localtime(&very_first_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u - ", tmp, very_first_event.milli); btm = localtime(&very_last_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u\n", tmp, very_last_event.milli); } printf("Selected time for report: "); { struct tm *btm; char tmp[48]; if (start_time) btm = localtime(&start_time); else btm = localtime(&very_first_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s - ", tmp); if (end_time) btm = localtime(&end_time); else btm = localtime(&very_last_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); if (end_time) printf("%s\n", tmp); else printf("%s.%03u\n", tmp, very_last_event.milli); } printf("Number of changes in configuration: %lu\n", sd.changes); printf("Number of changes to accounts, groups, or roles: %lu\n", sd.acct_changes); printf("Number of logins: %lu\n", sd.good_logins); printf("Number of failed logins: %lu\n", sd.bad_logins); printf("Number of authentications: %lu\n", sd.good_auth); printf("Number of failed authentications: %lu\n", sd.bad_auth); printf("Number of users: %u\n", sd.users.cnt); printf("Number of terminals: %u\n", sd.terms.cnt); printf("Number of host names: %u\n", sd.hosts.cnt); printf("Number of executables: %u\n", sd.exes.cnt); printf("Number of commands: %u\n", sd.comms.cnt); printf("Number of files: %u\n", sd.files.cnt); printf("Number of AVC's: %lu\n", sd.avcs); printf("Number of MAC events: %lu\n", sd.mac); printf("Number of failed syscalls: %lu\n", sd.failed_syscalls); printf("Number of anomaly events: %lu\n", sd.anomalies); printf("Number of responses to anomaly events: %lu\n", sd.responses); printf("Number of crypto events: %lu\n", sd.crypto); printf("Number of integrity events: %lu\n", sd.integ); printf("Number of virt events: %lu\n", sd.virt); printf("Number of keys: %u\n", sd.keys.cnt); printf("Number of process IDs: %u\n", sd.pids.cnt); printf("Number of events: %lu\n", sd.events); printf("\n"); } static void do_file_summary_output(slist *sptr) { const snode *sn; if (sptr->cnt == 0) { printf("\n\n"); return; } slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { printf("%u ", sn->hits); safe_print_string(sn->str, 1); sn=slist_next(sptr); } } static void do_string_summary_output(slist *sptr) { const snode *sn; if (sptr->cnt == 0) { printf("\n\n"); return; } slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { printf("%u %s\n", sn->hits, sn->str); sn=slist_next(sptr); } } static void do_user_summary_output(slist *sptr) { const snode *sn; if (sptr->cnt == 0) { printf("\n\n"); return; } slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { long uid; char name[64]; if (sn->str[0] == '-' || isdigit((unsigned char)sn->str[0])) { uid = strtol(sn->str, NULL, 10); printf("%u ", sn->hits); safe_print_string(aulookup_uid(uid, name, sizeof(name)), 1); } else { printf("%u ", sn->hits); safe_print_string(sn->str, 1); } sn=slist_next(sptr); } } static void do_int_summary_output(ilist *sptr) { const int_node *in; if (sptr->cnt == 0) { printf("\n\n"); return; } ilist_first(sptr); in=ilist_get_cur(sptr); while (in) { printf("%u %d\n", in->hits, in->num); in=ilist_next(sptr); } } static void do_syscall_summary_output(slist *sptr) { const snode *sn; if (sptr->cnt == 0) { printf("\n\n"); return; } slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { printf("%u ", sn->hits); safe_print_string(sn->str, 1); sn=slist_next(sptr); } } static void do_type_summary_output(ilist *sptr) { const int_node *in; if (sptr->cnt == 0) { printf("\n\n"); return; } ilist_first(sptr); in=ilist_get_cur(sptr); while (in) { const char *name = audit_msg_type_to_name(in->num); if (report_format == RPT_DEFAULT) printf("%u %d\n", in->hits, in->num); else printf("%u %s\n", in->hits, name); in=ilist_next(sptr); } } audit-userspace-4.0.5/src/aureport-scan.c000066400000000000000000000527521501761310600203470ustar00rootroot00000000000000/* * aureport-scan.c - Extract interesting fields and check for match * Copyright (c) 2005-06,2008,2011,2014-15 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include "libaudit.h" #include "aureport-options.h" #include "ausearch-parse.h" #include "ausearch-string.h" #include "ausearch-lookup.h" #include "aureport-scan.h" static void do_summary_total(llist *l); static int per_event_summary(llist *l); static int per_event_detailed(llist *l); summary_data sd; /* This function inits the counters */ void reset_counters(void) { sd.changes = 0UL; sd.crypto = 0UL; sd.acct_changes = 0UL; sd.good_logins = 0UL; sd.bad_logins = 0UL; sd.good_auth = 0UL; sd.bad_auth = 0UL; sd.events = 0UL; sd.avcs = 0UL; sd.mac = 0UL; sd.failed_syscalls = 0UL; sd.anomalies = 0UL; sd.responses = 0UL; sd.virt = 0UL; sd.integ = 0UL; slist_create(&sd.users); slist_create(&sd.terms); slist_create(&sd.files); slist_create(&sd.hosts); slist_create(&sd.exes); slist_create(&sd.comms); slist_create(&sd.avc_objs); slist_create(&sd.keys); ilist_create(&sd.pids); slist_create(&sd.sys_list); ilist_create(&sd.anom_list); ilist_create(&sd.mac_list); ilist_create(&sd.resp_list); ilist_create(&sd.crypto_list); ilist_create(&sd.virt_list); ilist_create(&sd.integ_list); } /* This function inits the counters */ void destroy_counters(void) { sd.changes = 0UL; sd.crypto = 0UL; sd.acct_changes = 0UL; sd.good_logins = 0UL; sd.bad_logins = 0UL; sd.good_auth = 0UL; sd.bad_auth = 0UL; sd.events = 0UL; sd.avcs = 0UL; sd.mac = 0UL; sd.failed_syscalls = 0UL; sd.anomalies = 0UL; sd.responses = 0UL; sd.virt = 0UL; sd.integ = 0UL; slist_clear(&sd.users); slist_clear(&sd.terms); slist_clear(&sd.files); slist_clear(&sd.hosts); slist_clear(&sd.exes); slist_clear(&sd.comms); slist_clear(&sd.avc_objs); slist_clear(&sd.keys); ilist_clear(&sd.pids); slist_clear(&sd.sys_list); ilist_clear(&sd.anom_list); ilist_create(&sd.mac_list); ilist_clear(&sd.resp_list); ilist_create(&sd.crypto_list); ilist_create(&sd.virt_list); ilist_create(&sd.integ_list); } /* This function will return 0 on no match and 1 on match */ static int classify_success(const llist *l) { //printf("%d,succ=%d:%d\n", l->head->type, event_failed, l->s.success); // If match only failed... if (event_failed == F_FAILED) return l->s.success == S_FAILED ? 1 : 0; // If match only success... if (event_failed == F_SUCCESS) return l->s.success == S_SUCCESS ? 1 : 0; // Otherwise...we don't care so pretend it matched return 1; } /* This function will return 0 on no match and 1 on match */ static int classify_conf(const llist *l) { int rc = 1; extern int no_config; switch (l->head->type) { case AUDIT_CONFIG_CHANGE: if (no_config) rc = 0; break; case AUDIT_USYS_CONFIG: break; case AUDIT_ADD_USER: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_DEL_USER: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_ADD_GROUP: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_DEL_GROUP: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_MAC_CIPSOV4_ADD: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_MAC_CIPSOV4_DEL: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_MAC_MAP_ADD: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_MAC_MAP_DEL: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_MAC_IPSEC_ADDSA: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_MAC_IPSEC_DELSA: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_MAC_IPSEC_ADDSPD: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_MAC_IPSEC_DELSPD: if (event_conf_act == C_ADD) rc = 0; break; case AUDIT_MAC_UNLBL_STCADD: if (event_conf_act == C_DEL) rc = 0; break; case AUDIT_MAC_UNLBL_STCDEL: if (event_conf_act == C_ADD) rc = 0; break; default: break; } //printf("conf=%d:%d\n", l->head->type, rc); return rc; } /* * This function performs that matching of search params with the record. * It returns 1 on a match, and 0 if no match. */ int scan(llist *l) { int rc = extract_search_items(l); if (rc == 0) { if (event_node_list) { const snode *sn; int found=0; slist *sptr = event_node_list; if (l->e.node == NULL) return 0; slist_first(sptr); sn=slist_get_cur(sptr); while (sn && !found) { if (sn->str && (!strcmp(sn->str, l->e.node))) found++; else sn=slist_next(sptr); } if (!found) return 0; } if (classify_success(l) && classify_conf(l)) return 1; return 0; } return 0; } int per_event_processing(llist *l) { int rc; switch (report_detail) { case D_SUM: rc = per_event_summary(l); break; case D_DETAILED: rc = per_event_detailed(l); break; case D_SPECIFIC: default: rc = 0; break; } return rc; } static int per_event_summary(llist *l) { int rc = 0; switch (report_type) { case RPT_SUMMARY: do_summary_total(l); rc = 1; break; case RPT_AVC: if (list_find_msg(l, AUDIT_AVC)) { if (alist_find_avc(l->s.avc)) { do { slist_add_if_uniq(&sd.avc_objs, l->s.avc->cur->tcontext); } while (alist_next_avc(l->s.avc)); } } else { if (list_find_msg(l, AUDIT_USER_AVC)) { if (alist_find_avc(l->s.avc)) { do { slist_add_if_uniq( &sd.avc_objs, l->s.avc->cur->tcontext); } while (alist_next_avc( l->s.avc)); } } } break; case RPT_MAC: if (list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_MAP_DEL)) { ilist_add_if_uniq(&sd.mac_list, l->head->type, 0); } else { if (list_find_msg_range(l, AUDIT_FIRST_USER_LSPP_MSG, AUDIT_LAST_USER_LSPP_MSG)) { ilist_add_if_uniq(&sd.mac_list, l->head->type, 0); } } break; case RPT_INTEG: if (list_find_msg_range(l, AUDIT_INTEGRITY_FIRST_MSG, AUDIT_INTEGRITY_LAST_MSG)) { ilist_add_if_uniq(&sd.integ_list, l->head->type, 0); } break; case RPT_VIRT: if (list_find_msg_range(l, AUDIT_FIRST_VIRT_MSG, AUDIT_LAST_VIRT_MSG)) { ilist_add_if_uniq(&sd.virt_list, l->head->type, 0); } break; case RPT_CONFIG: /* We will borrow the pid list */ if (list_find_msg(l, AUDIT_CONFIG_CHANGE) || list_find_msg(l, AUDIT_DAEMON_CONFIG) || list_find_msg(l, AUDIT_USYS_CONFIG) || list_find_msg(l, AUDIT_NETFILTER_CFG) || list_find_msg(l, AUDIT_FEATURE_CHANGE) || list_find_msg(l, AUDIT_USER_MAC_CONFIG_CHANGE)|| list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_UNLBL_STCDEL)) { ilist_add_if_uniq(&sd.pids, l->head->type, 0); } break; case RPT_AUTH: if (list_find_msg(l, AUDIT_USER_AUTH)) { if (l->s.loginuid == -2 && l->s.acct) slist_add_if_uniq(&sd.users, l->s.acct); else { char name[64]; slist_add_if_uniq(&sd.users, aulookup_uid(l->s.loginuid, name, sizeof(name)) ); } } else if (list_find_msg(l, AUDIT_USER_MGMT)) { // Only count the failures if (l->s.success == S_FAILED) { if (l->s.loginuid == -2 && l->s.acct != NULL) slist_add_if_uniq(&sd.users, l->s.acct); else { char name[64]; slist_add_if_uniq(&sd.users, aulookup_uid( l->s.loginuid, name, sizeof(name)) ); } } } break; case RPT_LOGIN: if (list_find_msg(l, AUDIT_USER_LOGIN)) { if ((int)l->s.loginuid < 0 && l->s.acct) slist_add_if_uniq(&sd.users, l->s.acct); else { char name[64]; slist_add_if_uniq(&sd.users, aulookup_uid(l->s.loginuid, name, sizeof(name)) ); } } break; case RPT_ACCT_MOD: /* We will borrow the pid list */ if (list_find_msg(l, AUDIT_USER_CHAUTHTOK) || list_find_msg_range(l, AUDIT_ADD_USER, AUDIT_DEL_GROUP) || list_find_msg(l, AUDIT_USER_MGMT) || list_find_msg(l, AUDIT_GRP_MGMT) || list_find_msg_range(l, AUDIT_ROLE_ASSIGN, AUDIT_ROLE_REMOVE)) { ilist_add_if_uniq(&sd.pids, l->head->type, 0); } break; case RPT_EVENT: /* We will borrow the pid list */ if (l->head->type != -1) { ilist_add_if_uniq(&sd.pids, l->head->type, 0); } break; case RPT_FILE: if (l->s.filename) { const snode *sn; slist *sptr = l->s.filename; slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { if (sn->str) slist_add_if_uniq(&sd.files, sn->str); sn=slist_next(sptr); } } break; case RPT_HOST: if (l->s.hostname) slist_add_if_uniq(&sd.hosts, l->s.hostname); break; case RPT_PID: if (l->s.pid != -1) { ilist_add_if_uniq(&sd.pids, l->s.pid, 0); } break; case RPT_SYSCALL: if (l->s.syscall > 0) { char tmp[32]; aulookup_syscall(l, tmp, 32); slist_add_if_uniq(&sd.sys_list, tmp); } break; case RPT_TERM: if (l->s.terminal) slist_add_if_uniq(&sd.terms, l->s.terminal); break; case RPT_USER: if (l->s.loginuid != -2) { char tmp[32]; aulookup_uid(l->s.loginuid, tmp, 32); slist_add_if_uniq(&sd.users, tmp); } break; case RPT_EXE: if (l->s.exe) slist_add_if_uniq(&sd.exes, l->s.exe); break; case RPT_COMM: if (l->s.comm) slist_add_if_uniq(&sd.comms, l->s.comm); break; case RPT_ANOMALY: if (list_find_msg_range(l, AUDIT_FIRST_ANOM_MSG, AUDIT_LAST_ANOM_MSG)) { ilist_add_if_uniq(&sd.anom_list, l->head->type, 0); } else { if (list_find_msg_range(l, AUDIT_FIRST_KERN_ANOM_MSG, AUDIT_LAST_KERN_ANOM_MSG) || list_find_msg(l, AUDIT_SECCOMP) ) { ilist_add_if_uniq(&sd.anom_list, l->head->type, 0); } } break; case RPT_RESPONSE: if (list_find_msg_range(l, AUDIT_FIRST_ANOM_RESP, AUDIT_LAST_ANOM_RESP)) { ilist_add_if_uniq(&sd.resp_list, l->head->type, 0); } break; case RPT_CRYPTO: if (list_find_msg_range(l, AUDIT_FIRST_KERN_CRYPTO_MSG, AUDIT_LAST_KERN_CRYPTO_MSG)) { ilist_add_if_uniq(&sd.crypto_list, l->head->type, 0); } else { if (list_find_msg_range(l, AUDIT_FIRST_CRYPTO_MSG, AUDIT_LAST_CRYPTO_MSG)) { ilist_add_if_uniq(&sd.crypto_list, l->head->type, 0); } } break; case RPT_KEY: if (l->s.key) { const snode *sn; slist *sptr = l->s.key; slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { if (sn->str && strcmp(sn->str, "(null)")) slist_add_if_uniq(&sd.keys, sn->str); sn=slist_next(sptr); } } break; case RPT_TTY: UNIMPLEMENTED; break; default: break; } return rc; } static int per_event_detailed(llist *l) { int rc = 0; switch (report_type) { case RPT_AVC: if (list_find_msg(l, AUDIT_AVC)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_USER_AVC)) { print_per_event_item(l); rc = 1; } break; case RPT_MAC: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_UNLBL_STCDEL)) { print_per_event_item(l); rc = 1; } else { if (list_find_msg_range(l, AUDIT_FIRST_USER_LSPP_MSG, AUDIT_LAST_USER_LSPP_MSG)) { print_per_event_item(l); rc = 1; } } } break; case RPT_INTEG: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_INTEGRITY_FIRST_MSG, AUDIT_INTEGRITY_LAST_MSG)) { print_per_event_item(l); rc = 1; } } break; case RPT_VIRT: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_FIRST_VIRT_MSG, AUDIT_LAST_VIRT_MSG)) { print_per_event_item(l); rc = 1; } } break; case RPT_CONFIG: if (list_find_msg(l, AUDIT_CONFIG_CHANGE)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_DAEMON_CONFIG)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_USYS_CONFIG)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_NETFILTER_CFG)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_FEATURE_CHANGE)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_USER_MAC_CONFIG_CHANGE)) { print_per_event_item(l); rc = 1; } else if (list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_UNLBL_STCDEL)) { print_per_event_item(l); rc = 1; } break; case RPT_AUTH: if (list_find_msg(l, AUDIT_USER_AUTH)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_USER_MGMT)) { // Only count the failed acct if (l->s.success == S_FAILED) { print_per_event_item(l); rc = 1; } } break; case RPT_LOGIN: if (list_find_msg(l, AUDIT_USER_LOGIN)) { print_per_event_item(l); rc = 1; } break; case RPT_ACCT_MOD: if (list_find_msg(l, AUDIT_USER_CHAUTHTOK)) { print_per_event_item(l); rc = 1; } else if (list_find_msg_range(l, AUDIT_ADD_USER, AUDIT_DEL_GROUP)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_USER_MGMT)) { print_per_event_item(l); rc = 1; } else if (list_find_msg(l, AUDIT_GRP_MGMT)) { print_per_event_item(l); rc = 1; } else if (list_find_msg_range(l, AUDIT_ROLE_ASSIGN, AUDIT_ROLE_REMOVE)) { print_per_event_item(l); rc = 1; } break; case RPT_EVENT: list_first(l); if (report_detail == D_DETAILED) { print_per_event_item(l); rc = 1; } else { // specific event report UNIMPLEMENTED; } break; case RPT_FILE: list_first(l); if (report_detail == D_DETAILED) { if (l->s.filename) { print_per_event_item(l); rc = 1; } } else { // specific file report UNIMPLEMENTED; } break; case RPT_HOST: list_first(l); if (report_detail == D_DETAILED) { if (l->s.hostname) { print_per_event_item(l); rc = 1; } } else { // specific host report UNIMPLEMENTED; } break; case RPT_PID: list_first(l); if (report_detail == D_DETAILED) { if (l->s.pid >= 0) { print_per_event_item(l); rc = 1; } } else { // specific pid report UNIMPLEMENTED; } break; case RPT_SYSCALL: list_first(l); if (report_detail == D_DETAILED) { if (l->s.syscall) { print_per_event_item(l); rc = 1; } } else { // specific syscall report UNIMPLEMENTED; } break; case RPT_TERM: list_first(l); if (report_detail == D_DETAILED) { if (l->s.terminal) { print_per_event_item(l); rc = 1; } } else { // specific terminal report UNIMPLEMENTED; } break; case RPT_USER: list_first(l); if (report_detail == D_DETAILED) { if (l->s.uid != -1) { print_per_event_item(l); rc = 1; } } else { // specific user report UNIMPLEMENTED; } break; case RPT_EXE: list_first(l); if (report_detail == D_DETAILED) { if (l->s.exe) { print_per_event_item(l); rc = 1; } } else { // specific exe report UNIMPLEMENTED; } break; case RPT_COMM: list_first(l); if (report_detail == D_DETAILED) { if (l->s.comm) { print_per_event_item(l); rc = 1; } } else { // specific exe report UNIMPLEMENTED; } break; case RPT_ANOMALY: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_FIRST_ANOM_MSG, AUDIT_LAST_ANOM_MSG)) { print_per_event_item(l); rc = 1; } else { if (list_find_msg_range(l, AUDIT_FIRST_KERN_ANOM_MSG, AUDIT_LAST_KERN_ANOM_MSG) || list_find_msg(l, AUDIT_SECCOMP) ) { print_per_event_item(l); rc = 1; } } } else { // FIXME: specific anom report UNIMPLEMENTED; } break; case RPT_RESPONSE: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_FIRST_ANOM_RESP, AUDIT_LAST_ANOM_RESP)) { print_per_event_item(l); rc = 1; } } else { // FIXME: specific resp report UNIMPLEMENTED; } break; case RPT_CRYPTO: if (report_detail == D_DETAILED) { if (list_find_msg_range(l, AUDIT_FIRST_KERN_CRYPTO_MSG, AUDIT_LAST_KERN_CRYPTO_MSG)) { print_per_event_item(l); rc = 1; } else { if (list_find_msg_range(l, AUDIT_FIRST_CRYPTO_MSG, AUDIT_LAST_CRYPTO_MSG)) { print_per_event_item(l); rc = 1; } } } else { // FIXME: specific crypto report UNIMPLEMENTED; } break; case RPT_KEY: list_first(l); if (report_detail == D_DETAILED) { if (l->s.key) { slist_first(l->s.key); if (strcmp(l->s.key->cur->str, "(null)")) { print_per_event_item(l); rc = 1; } } } else { // specific key report UNIMPLEMENTED; } break; case RPT_TTY: if (l->head->type == AUDIT_TTY || l->head->type == AUDIT_USER_TTY) { print_per_event_item(l); rc = 1; } break; default: break; } return rc; } static void do_summary_total(llist *l) { // add events sd.events++; // add config changes if (list_find_msg(l, AUDIT_CONFIG_CHANGE)) sd.changes++; if (list_find_msg(l, AUDIT_DAEMON_CONFIG)) sd.changes++; if (list_find_msg(l, AUDIT_USYS_CONFIG)) sd.changes++; if (list_find_msg(l, AUDIT_NETFILTER_CFG)) sd.changes++; if (list_find_msg(l, AUDIT_FEATURE_CHANGE)) sd.changes++; if (list_find_msg(l, AUDIT_USER_MAC_CONFIG_CHANGE)) sd.changes++; list_first(l); if (list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_UNLBL_STCDEL)) sd.changes++; // add acct changes if (list_find_msg(l, AUDIT_USER_CHAUTHTOK)) sd.acct_changes++; if (list_find_msg_range(l, AUDIT_ADD_USER, AUDIT_DEL_GROUP)) sd.acct_changes++; if (list_find_msg(l, AUDIT_USER_MGMT)) sd.acct_changes++; if (list_find_msg(l, AUDIT_GRP_MGMT)) sd.acct_changes++; list_first(l); if (list_find_msg_range(l, AUDIT_ROLE_ASSIGN, AUDIT_ROLE_REMOVE)) sd.acct_changes++; // Crypto list_first(l); if (list_find_msg_range(l, AUDIT_FIRST_KERN_CRYPTO_MSG, AUDIT_LAST_KERN_CRYPTO_MSG)) sd.crypto++; if (list_find_msg_range(l, AUDIT_FIRST_CRYPTO_MSG, AUDIT_LAST_CRYPTO_MSG)) sd.crypto++; // add logins if (list_find_msg(l, AUDIT_USER_LOGIN)) { if (l->s.success == S_SUCCESS) sd.good_logins++; else if (l->s.success == S_FAILED) sd.bad_logins++; } // add use of auth if (list_find_msg(l, AUDIT_USER_AUTH)) { if (l->s.success == S_SUCCESS) sd.good_auth++; else if (l->s.success == S_FAILED) sd.bad_auth++; } else if (list_find_msg(l, AUDIT_USER_MGMT)) { // Only count the failures if (l->s.success == S_FAILED) sd.bad_auth++; } else if (list_find_msg(l, AUDIT_GRP_AUTH)) { if (l->s.success == S_SUCCESS) sd.good_auth++; else if (l->s.success == S_FAILED) sd.bad_auth++; } // add users if (l->s.loginuid != -2) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%d", l->s.loginuid); slist_add_if_uniq(&sd.users, tmp); } // add terminals if (l->s.terminal) slist_add_if_uniq(&sd.terms, l->s.terminal); // add hosts if (l->s.hostname) slist_add_if_uniq(&sd.hosts, l->s.hostname); // add execs if (l->s.exe) slist_add_if_uniq(&sd.exes, l->s.exe); // add comms if (l->s.comm) slist_add_if_uniq(&sd.comms, l->s.comm); // add files if (l->s.filename) { const snode *sn; slist *sptr = l->s.filename; slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { if (sn->str) slist_add_if_uniq(&sd.files, sn->str); sn=slist_next(sptr); } } // add avcs if (list_find_msg(l, AUDIT_AVC)) sd.avcs++; else if (list_find_msg(l, AUDIT_USER_AVC)) sd.avcs++; // MAC list_first(l); if (list_find_msg_range(l, AUDIT_MAC_POLICY_LOAD, AUDIT_MAC_UNLBL_STCDEL)) sd.mac++; if (list_find_msg_range(l, AUDIT_FIRST_USER_LSPP_MSG, AUDIT_LAST_USER_LSPP_MSG)) sd.mac++; // Virt list_first(l); if (list_find_msg_range(l, AUDIT_FIRST_VIRT_MSG, AUDIT_LAST_VIRT_MSG)) sd.virt++; // Integrity list_first(l); if (list_find_msg_range(l, AUDIT_INTEGRITY_FIRST_MSG, AUDIT_INTEGRITY_LAST_MSG)) sd.integ++; // add failed syscalls if (l->s.success == S_FAILED && l->s.syscall > 0) sd.failed_syscalls++; // add pids if (l->s.pid != -1) { ilist_add_if_uniq(&sd.pids, l->s.pid, 0); } // add anomalies if (list_find_msg_range(l, AUDIT_FIRST_ANOM_MSG, AUDIT_LAST_ANOM_MSG)) sd.anomalies++; if (list_find_msg_range(l, AUDIT_FIRST_KERN_ANOM_MSG, AUDIT_LAST_KERN_ANOM_MSG)) sd.anomalies++; // add response to anomalies if (list_find_msg_range(l, AUDIT_FIRST_ANOM_RESP, AUDIT_LAST_ANOM_RESP)) sd.responses++; // add keys if (l->s.key) { const snode *sn; slist *sptr = l->s.key; slist_first(sptr); sn=slist_get_cur(sptr); while (sn) { if (sn->str && strcmp(sn->str, "(null)")) { slist_add_if_uniq(&sd.keys, sn->str); } sn=slist_next(sptr); } } } audit-userspace-4.0.5/src/aureport-scan.h000066400000000000000000000035511501761310600203450ustar00rootroot00000000000000/* aureport-scan.h -- * Copyright 2005-06,2008,2014 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * */ #ifndef AUREPORT_SCAN_H #define AUREPORT_SCAN_H #include "ausearch-llist.h" #include "ausearch-int.h" typedef struct sdata { slist users; slist terms; slist files; slist hosts; slist exes; slist comms; slist avc_objs; slist keys; ilist pids; slist sys_list; ilist anom_list; ilist resp_list; ilist mac_list; ilist crypto_list; ilist virt_list; ilist integ_list; unsigned long changes; unsigned long crypto; unsigned long acct_changes; unsigned long good_logins; unsigned long bad_logins; unsigned long good_auth; unsigned long bad_auth; unsigned long events; unsigned long avcs; unsigned long mac; unsigned long failed_syscalls; unsigned long anomalies; unsigned long responses; unsigned long virt; unsigned long integ; } summary_data; void reset_counters(void); void destroy_counters(void); int scan(llist *l); int per_event_processing(llist *l); void print_title(void); void print_per_event_item(llist *l); void print_wrap_up(void); extern summary_data sd; #endif audit-userspace-4.0.5/src/aureport.c000066400000000000000000000207561501761310600174240ustar00rootroot00000000000000/* * aureport.c - main file for aureport utility * Copyright 2005-08, 2010,11,2013,2020 Red Hat * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libaudit.h" #include "auditd-config.h" #include "aureport-options.h" #include "aureport-scan.h" #include "ausearch-lol.h" #include "ausearch-lookup.h" #include "auparse-idata.h" #include "ausearch-parse.h" extern event very_first_event; event very_last_event; static FILE *log_fd = NULL; static lol lo; static int found = 0; static int files_to_process = 0; // Logs left when processing multiple static int userfile_is_dir = 0; static struct daemon_conf config; static int process_logs(void); static int process_log_fd(const char *filename); static int process_stdin(void); static int process_file(char *filename); static int get_event(llist **); extern char *user_file; extern int force_logs; /* * User space configuration items */ extern time_t arg_eoe_timeout; static int is_pipe(int fd) { struct stat st; if (fstat(fd, &st) == 0) { if (S_ISFIFO(st.st_mode)) return 1; } return 0; } int main(int argc, char *argv[]) { struct rlimit limit; int rc; /* Check params and build regexpr */ setlocale (LC_ALL, ""); if (check_params(argc, argv)) return 1; /* Raise the rlimits in case we're being started from a shell * with restrictions. Not a fatal error. */ limit.rlim_cur = RLIM_INFINITY; limit.rlim_max = RLIM_INFINITY; setrlimit(RLIMIT_FSIZE, &limit); setrlimit(RLIMIT_CPU, &limit); set_aumessage_mode(MSG_STDERR, DBG_NO); (void) umask( umask( 077 ) | 027 ); very_first_event.sec = 0; reset_counters(); /* Load config so we know where logs are and eoe_timeout */ if (load_config(&config, TEST_SEARCH)) fprintf(stderr, "NOTE - using built-in logs: %s\n", config.log_file); /* Set timeout from the config file */ lol_set_eoe_timeout((time_t)config.end_of_event_timeout); /* * If an override was specified on the command line, override the config */ if (arg_eoe_timeout != 0) lol_set_eoe_timeout((time_t)arg_eoe_timeout); print_title(); if (arg_eoe_timeout != 0) { lol_set_eoe_timeout(arg_eoe_timeout); } lol_create(&lo); if (user_file) { struct stat sb; if (stat(user_file, &sb) == -1) { perror("stat"); return 1; } else { switch (sb.st_mode & S_IFMT) { case S_IFDIR: userfile_is_dir = 1; rc = process_logs(); break; case S_IFREG: default: rc = process_file(user_file); break; } } } else if (force_logs) rc = process_logs(); else if (is_pipe(0)) rc = process_stdin(); else rc = process_logs(); lol_clear(&lo); if (rc) return rc; if (!found && report_detail == D_DETAILED && report_type != RPT_TIME) { printf("\n\n"); destroy_counters(); aulookup_destroy_uid_list(); return 1; } else print_wrap_up(); destroy_counters(); aulookup_destroy_uid_list(); lookup_uid_destroy_list(); free(user_file); return 0; } static int process_logs(void) { char *filename; size_t len; int num = 0; if (user_file && userfile_is_dir) { char dirname[MAXPATHLEN+1]; clear_config (&config); strncpy(dirname, user_file, MAXPATHLEN-32); if (dirname[strlen(dirname)-1] != '/') strcat(dirname, "/"); strcat (dirname, "audit.log"); free((void *)config.log_file); config.log_file=strdup(dirname); fprintf(stderr, "NOTE - using logs in %s\n", config.log_file); } /* for each file */ len = strlen(config.log_file) + 16; filename = malloc(len); if (!filename) { fprintf(stderr, "No memory\n"); free_config(&config); return 1; } /* Find oldest log file */ snprintf(filename, len, "%s", config.log_file); do { if (access(filename, R_OK) != 0) break; // FIXME: do a time check and put them on linked list for later num++; snprintf(filename, len, "%s.%d", config.log_file, num); } while (1); num--; /* * We note how many files we need to process */ files_to_process = num; /* Got it, now process logs from last to first */ if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else snprintf(filename, len, "%s", config.log_file); do { int ret; if ((ret = process_file(filename))) { free(filename); free_config(&config); return ret; } /* Get next log file */ files_to_process--; /* one less file to process */ num--; if (num > 0) snprintf(filename, len, "%s.%d", config.log_file, num); else if (num == 0) snprintf(filename, len, "%s", config.log_file); else break; } while (1); free(filename); free_config(&config); return 0; } static void process_event(llist *entries) { if (scan(entries)) { // If its a single event or SYSCALL load interpretations if ((entries->cnt == 1) || (entries->head->type == AUDIT_SYSCALL)) _auparse_load_interpretations(entries->head->interp); // This is the per entry action item if (per_event_processing(entries)) found = 1; _auparse_free_interpretations(); } } static int process_log_fd(const char *filename) { llist *entries; // entries in a record int ret; int first = 0; event first_event, last_event; last_event.sec = 0; last_event.milli = 0; /* For each event in file */ do { ret = get_event(&entries); if ((ret != 0)||(entries->cnt == 0)||(entries->head == NULL)) break; // If report is RPT_TIME or RPT_SUMMARY, get if (report_type <= RPT_SUMMARY) { if (first == 0) { list_get_event(entries, &first_event); first = 1; } list_get_event(entries, &last_event); } // Are we within time range? if (start_time == 0 || entries->e.sec >= start_time) { if (end_time == 0 || entries->e.sec <= end_time) { process_event(entries); } } list_clear(entries); free(entries); } while (ret == 0); fclose(log_fd); // This is the per file action items very_last_event.sec = last_event.sec; very_last_event.milli = last_event.milli; if (report_type == RPT_TIME) { if (first == 0) { printf("%s: no records\n", filename); } else { struct tm *btm; char tmp[32]; printf("%s: ", filename); btm = localtime(&first_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u - ", tmp, first_event.milli); btm = localtime(&last_event.sec); if (btm) strftime(tmp, sizeof(tmp), "%x %T", btm); else strcpy(tmp, "?"); printf("%s.%03u\n", tmp, last_event.milli); } } return 0; } static int process_stdin(void) { log_fd = stdin; return process_log_fd("stdin"); } static int process_file(char *filename) { log_fd = fopen(filename, "rm"); if (log_fd == NULL) { fprintf(stderr, "Error opening %s (%s)\n", filename, strerror(errno)); return 1; } __fsetlocking(log_fd, FSETLOCKING_BYCALLER); return process_log_fd(filename); } /* * This function returns a linked list of all records in an event. * It returns 0 on success, 1 on eof, -1 on error. */ static int get_event(llist **l) { char *rc; char *buff = NULL; *l = get_ready_event(&lo); if (*l) return 0; while (1) { if (!buff) { buff = malloc(MAX_AUDIT_MESSAGE_LENGTH); if (!buff) return -1; } rc = fgets_unlocked(buff, MAX_AUDIT_MESSAGE_LENGTH, log_fd); if (rc) { if (lol_add_record(&lo, buff)) { *l = get_ready_event(&lo); if (*l) break; } } else { free(buff); if (feof_unlocked(log_fd)) { // Only mark all events complete if this is // the last file. if (files_to_process == 0) { terminate_all_events(&lo); } *l = get_ready_event(&lo); if (*l) return 0; else return 1; } else return -1; } } free(buff); return 0; } audit-userspace-4.0.5/src/ausearch-avc.c000066400000000000000000000075651501761310600201300ustar00rootroot00000000000000/* * ausearch-avc.c - Minimal linked list library for avcs * Copyright (c) 2006,2008,2014 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include "ausearch-avc.h" void alist_create(alist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; } anode *alist_next(alist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } static void alist_last(alist *l) { register anode* cur; if (l->head == NULL) return; // Start with cur in hopes that we don't start at beginning if (l->cur) cur = l->cur; else cur = l->head; // Loop until no next value while (cur->next) cur = cur->next; l->cur = cur; } int alist_append(alist *l, anode *node) { anode* newnode; newnode = malloc(sizeof(anode)); if (newnode == NULL) return 1; if (node->scontext) newnode->scontext = node->scontext; else newnode->scontext = NULL; if (node->tcontext) newnode->tcontext = node->tcontext; else newnode->tcontext = NULL; newnode->avc_result = node->avc_result; if (node->avc_perm) newnode->avc_perm = node->avc_perm; else newnode->avc_perm = NULL; if (node->avc_class) newnode->avc_class = node->avc_class; else newnode->avc_class = NULL; newnode->next = NULL; // Make sure cursor is at the end alist_last(l); // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } int alist_find_subj(alist *l) { register anode* node = l->head; while (node) { if (node->scontext) { l->cur = node; return 1; } else node = node->next; } return 0; } anode *alist_next_subj(alist *l) { if (l->cur == NULL) return NULL; while (l->cur->next) { l->cur=l->cur->next; if (l->cur->scontext) return l->cur; } return NULL; } int alist_find_obj(alist *l) { register anode* node = l->head; while (node) { if (node->tcontext) { l->cur = node; return 1; } else node = node->next; } return 0; } anode *alist_next_obj(alist *l) { if (l->cur == NULL) return NULL; while (l->cur->next) { l->cur=l->cur->next; if (l->cur->tcontext) return l->cur; } return NULL; } int alist_find_avc(alist *l) { register anode* node = l->head; while (node) { if (node->avc_result != AVC_UNSET) { l->cur = node; return 1; } else node = node->next; } return 0; } anode *alist_next_avc(alist *l) { if (l->cur == NULL) return NULL; while (l->cur->next) { l->cur=l->cur->next; if (l->cur->avc_result != AVC_UNSET) return l->cur; } return NULL; } void alist_clear(alist* l) { anode* nextnode; register anode* current; current = l->head; while (current) { nextnode=current->next; anode_clear(current); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } void anode_init(anode *an) { an->scontext = NULL; an->tcontext = NULL; an->avc_result = AVC_UNSET; an->avc_perm = NULL; an->avc_class = NULL; } void anode_clear(anode *an) { free(an->scontext); free(an->tcontext); free(an->avc_perm); free(an->avc_class); } audit-userspace-4.0.5/src/ausearch-avc.h000066400000000000000000000045511501761310600201250ustar00rootroot00000000000000/* * ausearch-avc.h - Header file for ausearch-string.c * Copyright (c) 2006,2008 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AU_AVC_HEADER #define AU_AVC_HEADER #include "config.h" #include #include "libaudit.h" typedef enum { AVC_UNSET, AVC_DENIED, AVC_GRANTED } avc_t; /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _anode{ char *scontext; // se linux subject context char *tcontext; // se linux object context avc_t avc_result; // se linux avc denied/granted char *avc_perm; // se linux avc permission mentioned char *avc_class; // se linux class mentioned struct _anode* next; // Next string node pointer } anode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { anode *head; // List head anode *cur; // Pointer to current node unsigned int cnt; // How many items in this list } alist; void alist_create(alist *l); static inline void alist_first(alist *l) { l->cur = l->head; } anode *alist_next(alist *l); static inline anode *alist_get_cur(const alist *l) { return l->cur; } int alist_append(alist *l, anode *node); void anode_init(anode *an); void anode_clear(anode *an); void alist_clear(alist* l); /* See if any subj exists in list */ int alist_find_subj(alist *l); anode *alist_next_subj(alist *l); /* See if any obj exists in list */ int alist_find_obj(alist *l); anode *alist_next_obj(alist *l); /* See if any avc exists in list */ int alist_find_avc(alist *l); anode *alist_next_avc(alist *l); #endif audit-userspace-4.0.5/src/ausearch-checkpt.c000066400000000000000000000153251501761310600207710ustar00rootroot00000000000000/* * ausearch-checkpt.c - ausearch checkpointing feature * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include #include "ausearch-checkpt.h" #define DBG 0 /* set to non-zero for debug */ #if SIZEOF_LONG < SIZEOF_TIME_T #define TIME_T_SPECIFIER "%lld" #else #define TIME_T_SPECIFIER "%ld" #endif /* Remember why we failed */ unsigned checkpt_failure = 0; /* * Remember the file we were processing when we had incomplete events. * We remember this via it's dev and inode */ static dev_t checkpt_dev = (dev_t)NULL; static ino_t checkpt_ino = (ino_t)NULL; /* Remember the last event output */ static event last_event = {0, 0, 0, NULL, 0}; /* Loaded values from a given checkpoint file */ dev_t chkpt_input_dev = (dev_t)NULL; ino_t chkpt_input_ino = (ino_t)NULL; event chkpt_input_levent = {0, 0, 0, NULL, 0}; /* * Record the dev_t and ino_t of the given file * * Returns: * 1 Failed to get status * 0 OK */ int set_ChkPtFileDetails(const char *fn) { struct stat sbuf; if (stat(fn, &sbuf) != 0) { fprintf(stderr, "Cannot stat audit file for checkpoint " "details - %s: %s\n", fn, strerror(errno)); checkpt_failure |= CP_STATFAILED; return 1; } checkpt_dev = sbuf.st_dev; checkpt_ino = sbuf.st_ino; return 0; } /* * Save the given event in the last_event record * Returns: * 1 no memory * 0 OK */ int set_ChkPtLastEvent(const event *e) { /* Set the event node if necessary */ if (e->node) { if (last_event.node) { if (strcmp(e->node, last_event.node) != 0) { free((void *)last_event.node); last_event.node = strdup(e->node); } } else last_event.node = strdup(e->node); if (last_event.node == NULL) { fprintf(stderr, "No memory to allocate " "checkpoint last event node name\n"); return 1; } } else { if (last_event.node) free((void *)last_event.node); last_event.node = NULL; } last_event.sec = e->sec; last_event.milli = e->milli; last_event.serial = e->serial; last_event.type = e->type; return 0; } /* Free all checkpoint memory */ void free_ChkPtMemory(void) { if (last_event.node) (void)free((void *)last_event.node); last_event.node = NULL; if (chkpt_input_levent.node) (void)free((void *)chkpt_input_levent.node); chkpt_input_levent.node = NULL; } /* * Save the checkpoint to the given file * Returns: * 1 io error * 0 OK */ void save_ChkPt(const char *fn) { FILE *fd; if ((fd = fopen(fn, "w")) == NULL) { fprintf(stderr, "Cannot open checkpoint file - %s: %s\n", fn, strerror(errno)); checkpt_failure |= CP_STATUSIO; return; } // Write the inode in decimal to make ls -i easier to use. fprintf(fd, "dev=0x%" PRIX64 "\ninode=%" PRIu64 "\n", (uint64_t)checkpt_dev, (uint64_t)checkpt_ino); fprintf(fd, "output=%s %lld.%03u:%lu 0x%X\n", last_event.node ? last_event.node : "-", (long long int)last_event.sec, last_event.milli, last_event.serial, last_event.type); fclose(fd); } /* * Parse a checkpoint file "output=" record * Returns * 1 failed to parse or no memory * 0 parsed OK */ static int parse_checkpt_event(char *lbuf, int ndix, event *e) { char *rest; /* * Find the space after the node, then make it '\0' so * we terminate the node value. We leave 'rest' at the start * of the event time/serial element */ rest = strchr(&lbuf[ndix], ' '); if (rest == NULL) { fprintf(stderr, "Malformed output/event checkpoint line " "near node - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; return 1; } *rest++ = '\0'; if (lbuf[ndix] == '-') e->node = NULL; else { e->node = strdup(&lbuf[ndix]); if (e->node == NULL) { fprintf(stderr, "No memory for node when loading " "checkpoint line - [%s]\n", lbuf); checkpt_failure |= CP_NOMEM; return 1; } } if (sscanf(rest, TIME_T_SPECIFIER ".%03u:%lu 0x%X", &e->sec, &e->milli, &e->serial, &e->type) != 4) { fprintf(stderr, "Malformed output/event checkpoint line " "after node - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; return 1; } return 0; } /* * Load the checkpoint from the given file * Returns: * < -1 error * == -1 no file present * == 0 loaded data */ int load_ChkPt(const char *fn) { #define MAX_LN 1023 FILE *fd; char lbuf[MAX_LN]; if ((fd = fopen(fn, "r")) == NULL) { if (errno == ENOENT) return -1; fprintf(stderr, "Cannot open checkpoint file - %s: %s\n", fn, strerror(errno)); return -2; } chkpt_input_levent.node = NULL; while (fgets(lbuf, MAX_LN, fd) != NULL) { size_t len = strlen(lbuf); if (len && lbuf[len - 1] == '\n') /* drop the newline */ lbuf[len - 1] = '\0'; if (strncmp(lbuf, "dev=", 4) == 0) { errno = 0; chkpt_input_dev = (dev_t)strtoull(&lbuf[4], NULL, 16); if (errno) { fprintf(stderr, "Malformed dev checkpoint " "line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } else if (strncmp(lbuf, "inode=", 6) == 0) { errno = 0; chkpt_input_ino = (ino_t)strtoull(&lbuf[6], NULL, 0); if (errno) { fprintf(stderr, "Malformed inode checkpoint " "line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } else if (strncmp(lbuf, "output=", 7) == 0) { free((void *)chkpt_input_levent.node); chkpt_input_levent.node = NULL; if (parse_checkpt_event(lbuf, 7, &chkpt_input_levent)) break; } else { fprintf(stderr, "Unknown checkpoint line - [%s]\n", lbuf); checkpt_failure |= CP_STATUSBAD; break; } } if ( (chkpt_input_ino == (ino_t)NULL) || (chkpt_input_dev == (dev_t)NULL) ) { fprintf(stderr, "Missing dev/inode lines from checkpoint " "file %s\n", fn); checkpt_failure |= CP_STATUSBAD; } fclose(fd); if (checkpt_failure) return -3; #if DBG { fprintf(stderr, "Loaded %s - dev: 0x%X, ino: 0x%X\n", fn, chkpt_input_dev, chkpt_input_ino); fprintf(stderr, "output:%s %lld.%03d:%lu 0x%X\n", chkpt_input_levent.node ? chkpt_input_levent.node : "-", (long long int)chkpt_input_levent.sec, chkpt_input_levent.milli, chkpt_input_levent.serial, chkpt_input_levent.type); } #endif /* DBG */ return 0; } audit-userspace-4.0.5/src/ausearch-checkpt.h000066400000000000000000000030501501761310600207660ustar00rootroot00000000000000/* * ausearch-checkpt.h - ausearch checkpointing feature header file * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef CHECKPT_HEADER #define CHECKPT_HEADER #include #include "ausearch-llist.h" int set_ChkPtFileDetails(const char *fn); int set_ChkPtLastEvent(const event *e); void free_ChkPtMemory(void); void save_ChkPt(const char *fn); int load_ChkPt(const char *fn); #define CP_NOMEM 0x0001 /* no memory when creating checkpoint list */ #define CP_STATFAILED 0x0002 /* stat() call on last log file failed */ #define CP_STATUSIO 0x0004 /* cannot open/read/write checkpoint file */ #define CP_STATUSBAD 0x0008 /* malformed status checkpoint entries */ #define CP_CORRUPTED 0x0010 /* corrupted times in checkpoint file */ extern unsigned checkpt_failure; extern dev_t chkpt_input_dev; extern ino_t chkpt_input_ino; extern event chkpt_input_levent; #endif /* CHECKPT_HEADER */ audit-userspace-4.0.5/src/ausearch-common.h000066400000000000000000000053531501761310600206450ustar00rootroot00000000000000/* ausearch-common.h -- * Copyright 2006-08,2010,2014,2016-17 Red Hat Inc., Durham, North Carolina. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Steve Grubb * Marcelo Henrique Cerri * */ #ifndef AUREPORT_COMMON_H #define AUREPORT_COMMON_H #include #include #include "ausearch-string.h" #include "auparse-defs.h" /* * MAX_EVENT_DELTA_SECS is the maximum number of seconds it would take for * auditd and the kernel to emit all of an events' records. Thus, when scanning * a list of audit records without any End of Event marker, we can determine if * all an event's records have been collected if we compare that event's time * with the time of the event we are currently scanning. If * MAX_EVENT_DELTA_SECS have passed, then the event is deamed to be complete * and we have all it's records. */ #define MAX_EVENT_DELTA_SECS 2 /* Global variables that describe what search is to be performed */ extern time_t start_time, end_time; extern unsigned int event_id; extern gid_t event_gid, event_egid; extern pid_t event_pid; extern int event_exact_match; extern uid_t event_uid, event_euid, event_loginuid; extern const char *event_tuid, *event_teuid, *event_tauid; extern slist *event_node_list; extern const char *event_comm; extern const char *event_filename; extern const char *event_hostname; extern const char *event_terminal; extern int event_syscall; extern int event_machine; extern const char *event_exe; extern int event_ua, event_ga; extern long long event_exit; extern int event_exit_is_set; extern const char *event_uuid; extern const char *event_vmname; typedef enum { F_BOTH, F_FAILED, F_SUCCESS } failed_t; typedef enum { C_NEITHER, C_ADD, C_DEL } conf_act_t; typedef enum { S_UNSET=-1, S_FAILED, S_SUCCESS } success_t; typedef enum { RPT_RAW, RPT_DEFAULT, RPT_INTERP, RPT_PRETTY, RPT_CSV, RPT_TEXT } report_t; extern failed_t event_failed; extern conf_act_t event_conf_act; extern success_t event_success; extern auparse_esc_t escape_mode; #endif audit-userspace-4.0.5/src/ausearch-int.c000066400000000000000000000063371501761310600201450ustar00rootroot00000000000000/* * ausearch-int.c - Minimal linked list library for integers * Copyright (c) 2005,2008 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include "ausearch-int.h" void ilist_create(ilist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; } int_node *ilist_next(ilist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } int ilist_append(ilist *l, int num, unsigned int hits, int aux) { int_node* newnode; newnode = malloc(sizeof(int_node)); if (newnode == NULL) return 1; newnode->num = num; newnode->hits = hits; newnode->aux1 = aux; newnode->next = NULL; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } void ilist_clear(ilist* l) { int_node* nextnode; register int_node* current; if (l == NULL) return; current = l->head; while (current) { nextnode=current->next; free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } int ilist_add_if_uniq(ilist *l, int num, int aux) { register int_node *cur, *prev; prev = cur = l->head; while (cur) { if (cur->num == num) { cur->hits++; return 0; } else if (num > cur->num) { prev = cur; cur = cur->next; } else { int head = 0; // Insert so list is from low to high if (cur == l->head) { l->head = NULL; head = 1; } else l->cur = prev; ilist_append(l, num, 1, aux); if (head) l->cur->next = prev; else l->cur->next = cur; return 1; } } if (prev) l->cur = prev; /* No matches, append to the end */ ilist_append(l, num, 1, aux); return 1; } // If lprev would be NULL, use l->head static void swap_nodes(int_node *lprev, int_node *left, int_node *right) { int_node *t = right->next; if (lprev) lprev->next = right; right->next = left; left->next = t; } // This will sort the list from most hits to least void ilist_sort_by_hits(ilist *l) { register int_node* cur, *prev; if (l->cnt <= 1) return; prev = cur = l->head; while (cur && cur->next) { /* If the next node is bigger */ if (cur->hits < cur->next->hits) { if (cur == l->head) { // Update the actual list head l->head = cur->next; prev = NULL; } swap_nodes(prev, cur, cur->next); // start over prev = cur = l->head; continue; } prev = cur; cur = cur->next; } // End with cur pointing at first record l->cur = l->head; } audit-userspace-4.0.5/src/ausearch-int.h000066400000000000000000000037071501761310600201500ustar00rootroot00000000000000/* * ausearch-int.h - Header file for ausearch-int.c * Copyright (c) 2005,2008 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUINT_HEADER #define AUINT_HEADER #include "config.h" /* This is the node of the linked list. Number & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _int_node{ int num; // The number unsigned int hits; // The number of times this was attempted to be added int aux1; // Extra spot for data struct _int_node* next; // Next string node pointer } int_node; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { int_node *head; // List head int_node *cur; // Pointer to current node unsigned int cnt; // How many items in this list } ilist; void ilist_create(ilist *l); static inline void ilist_first(ilist *l) { l->cur = l->head; } int_node *ilist_next(ilist *l); static inline int_node *ilist_get_cur(const ilist *l) { return l->cur; } int ilist_append(ilist *l, int num, unsigned int hits, int aux); void ilist_clear(ilist* l); /* append a number if its not already on the list */ int ilist_add_if_uniq(ilist *l, int num, int aux); void ilist_sort_by_hits(ilist *l); #endif audit-userspace-4.0.5/src/ausearch-llist.c000066400000000000000000000123541501761310600204760ustar00rootroot00000000000000/* * ausearch-llist.c - Minimal linked list library * Copyright (c) 2005-2008,2011,2016 Red Hat Inc. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * Marcelo Henrique Cerri */ #include #include #include "ausearch-llist.h" #include "auditd-config.h" void list_create(llist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; l->fmt = LF_RAW; l->e.milli = 0L; l->e.sec = 0L; l->e.serial = 0L; l->e.node = NULL; l->e.type = 0; l->s.gid = -1; l->s.egid = -1; l->s.ppid = -1; l->s.pid = -1; l->s.success = S_UNSET; l->s.uid = -1; l->s.euid = -1; l->s.loginuid = -2; l->s.hostname = NULL; l->s.filename = NULL; l->s.terminal = NULL; l->s.cwd = NULL; l->s.exe = NULL; l->s.key = NULL; l->s.comm = NULL; l->s.avc = NULL; l->s.acct = NULL; l->s.arch = 0; l->s.syscall = 0; l->s.session_id = -2; l->s.uuid = NULL; l->s.vmname = NULL; l->s.tuid = NULL; l->s.teuid = NULL; l->s.tauid = NULL; l->s.exit = 0; l->s.exit_is_set = 0; } void list_last(llist *l) { register lnode* node; if (l->head == NULL) return; node = l->head; while (node->next) node = node->next; l->cur = node; } lnode *list_next(llist *l) { if (l->cur == NULL) return NULL; l->cur = l->cur->next; return l->cur; } lnode *list_prev(llist *l) { if (l->cur == NULL) return NULL; if (l->cur->item == 0) return NULL; list_find_item(l, l->cur->item-1); return l->cur; } int list_append(llist *l, lnode *node) { lnode* newnode; newnode = malloc(sizeof(lnode)); if (newnode == NULL) return 1; if (node->message) newnode->message = node->message; else newnode->message = NULL; newnode->interp = node->interp; newnode->mlen = node->mlen; newnode->tlen = node->tlen; newnode->type = node->type; newnode->a0 = node->a0; newnode->a1 = node->a1; newnode->item = l->cnt; newnode->next = NULL; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else // Otherwise add pointer to newnode l->cur->next = newnode; // make newnode current l->cur = newnode; l->cnt++; return 0; } int list_find_item(llist *l, unsigned int i) { register lnode* node; if (l->cur && (l->cur->item <= i)) node = l->cur; /* Try to use where we are */ else node = l->head; /* Can't, start over */ while (node) { if (node->item == i) { l->cur = node; return 1; } else node = node->next; } return 0; } void list_clear(llist* l) { lnode* nextnode; register lnode* current; current = l->head; while (current) { nextnode=current->next; free(current->message); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; l->e.milli = 0L; l->e.sec = 0L; l->e.serial = 0L; free((char *)l->e.node); l->e.node = NULL; l->e.type = 0; l->s.gid = -1; l->s.egid = -1; l->s.ppid = -1; l->s.pid = -1; l->s.success = S_UNSET; l->s.uid = -1; l->s.euid = -1; l->s.loginuid = -2; free(l->s.hostname); l->s.hostname = NULL; if (l->s.filename) { slist_clear(l->s.filename); free(l->s.filename); l->s.filename = NULL; } free(l->s.terminal); l->s.terminal = NULL; free(l->s.cwd); l->s.cwd = NULL; free(l->s.exe); l->s.exe = NULL; if (l->s.key) { slist_clear(l->s.key); free(l->s.key); l->s.key = NULL; } free(l->s.comm); l->s.comm = NULL; if (l->s.avc) { alist_clear(l->s.avc); free(l->s.avc); l->s.avc = NULL; } free(l->s.acct); l->s.acct = NULL; l->s.arch = 0; l->s.syscall = 0; l->s.session_id = -2; free(l->s.uuid); l->s.uuid = NULL; free(l->s.vmname); l->s.vmname = NULL; free((void *)l->s.tuid); l->s.tuid = NULL; free((void *)l->s.teuid); l->s.teuid = NULL; free((void *)l->s.tauid); l->s.tauid = NULL; l->s.exit = 0; l->s.exit_is_set = 0; } int list_get_event(llist* l, event *e) { if (l == NULL || e == NULL) return 0; e->sec = l->e.sec; e->milli = l->e.milli; e->serial = l->e.serial; return 1; } lnode *list_find_msg(llist *l, int i) { register lnode* node; node = l->head; /* start at the beginning */ while (node) { if (node->type == i) { l->cur = node; return node; } else node = node->next; } return NULL; } lnode *list_find_msg_range(llist *l, int low, int high) { register lnode* node; if (high <= low) return NULL; node = l->head; /* Start at the beginning */ while (node) { if (node->type >= low && node->type <= high) { l->cur = node; return node; } else node = node->next; } return NULL; } audit-userspace-4.0.5/src/ausearch-llist.h000066400000000000000000000102741501761310600205020ustar00rootroot00000000000000/* * ausearch-llist.h - Header file for ausearch-llist.c * Copyright (c) 2005-2008, 2013-14,2016 Red Hat Inc. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * Marcelo Henrique Cerri */ #ifndef AULIST_HEADER #define AULIST_HEADER #include "config.h" #include #include "ausearch-string.h" #include "ausearch-avc.h" #include "ausearch-common.h" typedef struct { time_t sec; // Event seconds unsigned int milli; // millisecond of the timestamp unsigned long serial; // Serial number of the event const char *node; // Machine's node name int type; // type of first event } event; typedef struct { pid_t ppid; // parent process ID pid_t pid; // process ID uid_t uid; // user ID uid_t euid; // effective user ID uid_t loginuid; // login user ID gid_t gid; // group ID gid_t egid; // effective group ID success_t success; // success flag, 1 = yes, 0 = no, -1 = unset int arch; // arch int syscall; // syscall uint32_t session_id; // Login session id long long exit; // Syscall exit code int exit_is_set; // Syscall exit code is valid char *hostname; // remote hostname slist *filename; // filename list char *cwd; // current working dir char *exe; // executable slist *key; // key field char *terminal; // terminal char *comm; // comm name alist *avc; // avcs for the event char *acct; // account used when uid is invalid char *uuid; // virtual machine unique universal identifier char *vmname; // virtual machine name const char *tuid; // interpreted uid const char *teuid; // interpreted euid const char *tauid; // interpreted auid } search_items; /* This is the node of the linked list. Any data elements that are per * record goes here. */ typedef struct _lnode{ char *message; // The whole unparsed message char *interp; // Beginning of interpretations within message unsigned int mlen; // Length of the message up to separator unsigned int tlen; // Total message size int type; // message type (KERNEL, USER, LOGIN, etc) unsigned long long a0; // argv 0 unsigned long long a1; // argv 1 unsigned int item; // Which item of the same event struct _lnode* next; // Next node pointer } lnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { lnode *head; // List head lnode *cur; // Pointer to current node unsigned int cnt; // How many items in this list // Data we add as 1 per event event e; // event - time & serial number search_items s; // items in the record that are searchable int fmt; // The event's format (raw, enriched) } llist; void list_create(llist *l); static inline void list_first(llist *l) { l->cur = l->head; } void list_last(llist *l); lnode *list_next(llist *l); lnode *list_prev(llist *l); static inline lnode *list_get_cur(llist *l) { return l->cur; } int list_append(llist *l, lnode *node); void list_clear(llist* l); int list_get_event(llist* l, event *e); /* Given a numeric index, find that record. */ int list_find_item(llist *l, unsigned int i); /* Given a message type, find the matching node */ lnode *list_find_msg(llist *l, int i); /* Given two message types, find the first matching node */ lnode *list_find_msg_range(llist *l, int low, int high); #endif audit-userspace-4.0.5/src/ausearch-lol.c000066400000000000000000000245651501761310600201440ustar00rootroot00000000000000/* * ausearch-lol.c - linked list of linked lists library * Copyright (c) 2008,2010,2014,2016,2019,2021 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "ausearch-lol.h" #include #include #include #include #include #include "ausearch-common.h" #include "auditd-config.h" #include "common.h" #define ARRAY_LIMIT 80 static int ready = 0; event very_first_event; // End of Event timeout value (in seconds). This can be over-riden via configuration or command line argument. static time_t eoe_timeout = EOE_TIMEOUT; void lol_create(lol *lo) { int size = ARRAY_LIMIT * sizeof(lolnode); lo->maxi = -1; lo->limit = ARRAY_LIMIT; lo->array = (lolnode *)malloc(size); if (lo->array == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); lo->limit = 0; return; } memset(lo->array, 0, size); } void lol_clear(lol *lo) { int i; for (i=0; i<=lo->maxi; i++) { if (lo->array[i].status) { list_clear(lo->array[i].l); free(lo->array[i].l); } } free(lo->array); lo->array = NULL; lo->maxi = -1; } static void lol_append(lol *lo, llist *l) { int i; size_t new_size; lolnode *ptr; for(i=0; ilimit; i++) { lolnode *cur = &lo->array[i]; if (cur->status == L_EMPTY) { cur->l = l; cur->status = L_BUILDING; if (i > lo->maxi) lo->maxi = i; return; } } // Overran the array...lets make it bigger new_size = sizeof(lolnode) * (lo->limit + ARRAY_LIMIT); ptr = realloc(lo->array, new_size); if (ptr) { lo->array = ptr; memset(&lo->array[lo->limit], 0, sizeof(lolnode) * ARRAY_LIMIT); lo->array[i].l = l; lo->array[i].status = L_BUILDING; lo->maxi = i; lo->limit += ARRAY_LIMIT; } } static int str2event(char *s, event *e) { char *ptr; errno = 0; e->sec = strtoul(s, NULL, 10); if (errno || e->sec > (LONG_MAX - eoe_timeout -1)) return -1; ptr = strchr(s, '.'); if (ptr) { ptr++; e->milli = strtoul(ptr, NULL, 10); if (errno || e->milli > 999) return -1; s = ptr; } else e->milli = 0; ptr = strchr(s, ':'); if (ptr) { ptr++; e->serial = strtoul(ptr, NULL, 10); if (errno) return -1; } else e->serial = 0; return 0; } static int inline events_are_equal(event *e1, event *e2) { if (!(e1->serial == e2->serial && e1->milli == e2->milli && e1->sec == e2->sec)) return 0; if (e1->node && e2->node) { if (strcmp(e1->node, e2->node)) return 0; } else if (e1->node || e2->node) return 0; return 1; } // Returns -1 if e1 < e2, 0 if equal, and 1 if e1 > e2 static int compare_event_time(event *e1, event *e2) { if (e1->sec != e2->sec) { if (e1->sec > e2->sec) return 1; return -1; } if (e1->milli != e2->milli) { if (e1->milli > e2->milli) return 1; return -1; } if (e1->serial != e2->serial) { if (e1->serial > e2->serial) return 1; return -1; } return 0; } #ifndef HAVE_STRNDUPA #define strndupa(s, n) \ ({ \ const char *__old = (s); \ size_t __len = strnlen (__old, (n)); \ char *__new = (char *) alloca(__len + 1); \ __new[__len] = '\0'; \ (char *) memcpy (__new, __old, __len); \ }) #endif /* * This function will look at the line and pick out pieces of it. */ static int extract_timestamp(const char *b, event *e) { char *ptr, *tmp, *tnode, *ttype; e->node = NULL; if (*b == 'n') tmp = strndupa(b, 340); else tmp = strndupa(b, 80); ptr = audit_strsplit(tmp); if (ptr) { // Check to see if this is the node info if (*ptr == 'n') { tnode = ptr+5; ptr = audit_strsplit(NULL); if (ptr == NULL) return 0; } else tnode = NULL; // at this point we have type= ttype = ptr+5; // Now should be pointing to msg= ptr = audit_strsplit(NULL); // strlen is for fuzzers that make invalid lines if (ptr && strnlen(ptr, 20) > 18) { if (*(ptr+9) == '(') ptr+=9; else ptr = strchr(ptr, '('); if (ptr) { // now we should be pointed at the timestamp char *eptr; ptr++; eptr = strchr(ptr, ')'); if (eptr) *eptr = 0; if (str2event(ptr, e)) { fprintf(stderr, "Error extracting time stamp (%s)\n", ptr); return 0; } else if ((start_time && e->sec < start_time) || (end_time && e->sec > end_time)) { if (very_first_event.sec == 0) { very_first_event.sec = e->sec; very_first_event.milli = e->milli; } return 0; } else { // If no start time, any event is 1st if (very_first_event.sec == 0 && start_time == 0) { very_first_event.sec = e->sec; very_first_event.milli = e->milli; } if (tnode) e->node = strdup(tnode); e->type = audit_name_to_msg_type(ttype); } return 1; } // else we have a bad line } // else we have a bad line } // else we have a bad line return 0; } // This function will check events to see if they are complete // FIXME: Can we think of other ways to determine if the event is done? static void check_events(lol *lo, time_t sec) { int i; for(i=0;i<=lo->maxi; i++) { lolnode *cur = &lo->array[i]; if (cur->status == L_BUILDING) { // If eoe_timeout seconds have elapsed, we are done if (cur->l->e.sec + eoe_timeout <= sec) { cur->status = L_COMPLETE; ready++; } else if (audit_is_last_record(cur->l->e.type)) { // If known to be 1 record event, we are done cur->status = L_COMPLETE; ready++; } } } } // This function will check events to see if they are complete but not compare against a given time static void check_events_without_time(lol *lo) { int i; for(i=0;i<=lo->maxi; i++) { lolnode *cur = &lo->array[i]; if (cur->status == L_BUILDING) { /* We now iterate over the event's records but without affecting the node's current * pointer (cur->l->cur). That is, we don't call the list-* routines * We could jump to the last record in the list which is normally a PROCTITLE, but this * may not be guaranteed, so we check all record types */ lnode *ln = cur->l->head; while (ln) { if (audit_is_last_record(ln->type)) { cur->status = L_COMPLETE; ready++; break; } ln = ln->next; } } } } // This function adds a new record to an existing linked list // or creates a new one if its a new event int lol_add_record(lol *lo, char *buff) { int i, fmt; lnode n; event e; char *ptr; llist *l; // Short circuit if event is not of interest if (extract_timestamp(buff, &e) == 0) return 0; n.a0 = 0L; n.a1 = 0L; n.type = e.type; n.message = strdup(buff); if(n.message == NULL) { free((char *)e.node); fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); return 0; } ptr = strchr(n.message, AUDIT_INTERP_SEPARATOR); if (ptr) { n.mlen = ptr - n.message; if (n.mlen > MAX_AUDIT_MESSAGE_LENGTH) n.mlen = MAX_AUDIT_MESSAGE_LENGTH; *ptr = 0; n.interp = ptr + 1; // since we are most of the way down the string, scan from there ptr = strrchr(n.interp, 0x0a); if (ptr) { *ptr = 0; n.tlen = ptr - n.message; if (n.tlen > MAX_AUDIT_MESSAGE_LENGTH) n.tlen = MAX_AUDIT_MESSAGE_LENGTH; } else n.tlen = n.mlen; fmt = LF_ENRICHED; } else { ptr = strrchr(n.message, 0x0a); if (ptr) { *ptr = 0; n.mlen = ptr - n.message; if (n.mlen > MAX_AUDIT_MESSAGE_LENGTH) n.mlen = MAX_AUDIT_MESSAGE_LENGTH; } else n.mlen = strlen(n.message); n.interp = NULL; n.tlen = n.mlen; fmt = LF_RAW; } // Now see where this belongs for (i=0; i<=lo->maxi; i++) { if (lo->array[i].status == L_BUILDING) { l = lo->array[i].l; if (events_are_equal(&l->e, &e)) { free((char *)e.node); list_append(l, &n); if (fmt > l->fmt) l->fmt = fmt; return 1; } } } // Eat standalone EOE, main event was already marked complete if (e.type == AUDIT_EOE) { free((char *)e.node); free(n.message); return 0; } // Create new event and fill it in l = malloc(sizeof(llist)); if (l == NULL) { free((char *)e.node); free(n.message); fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); return 0; } list_create(l); l->e.milli = e.milli; l->e.sec = e.sec; l->e.serial = e.serial; l->e.node = e.node; l->e.type = e.type; l->fmt = fmt; list_append(l, &n); lol_append(lo, l); check_events(lo, e.sec); return 1; } // This function will mark all events as "done" void terminate_all_events(lol *lo) { int i; for (i=0; i<=lo->maxi; i++) { lolnode *cur = &lo->array[i]; if (cur->status == L_BUILDING) { cur->status = L_COMPLETE; ready++; } } } // This function will mark all events as complete if it can. void complete_all_events(lol *lo) { check_events_without_time(lo); } /* Search the list for any event that is ready to go. The caller * takes custody of the memory */ llist* get_ready_event(lol *lo) { int i; lolnode *lowest = NULL; if (ready == 0) return NULL; for (i=0; i<=lo->maxi; i++) { // Look for the event with the lowest time stamp lolnode *cur = &lo->array[i]; if (cur->status == L_EMPTY) continue; if (lowest == NULL) lowest = cur; else if (compare_event_time(&(lowest->l->e), &(cur->l->e)) == 1) lowest = cur; } if (lowest && lowest->status == L_COMPLETE) { lowest->status = L_EMPTY; ready--; // Try to consolidate the array so that we iterate // over a smaller portion next time if (lowest == &lo->array[lo->maxi]) { lolnode *ptr = lowest; while (ptr->status == L_EMPTY && lo->maxi > 0) { lo->maxi--; ptr = &lo->array[lo->maxi]; } } return lowest->l; } return NULL; } /* * lol_set_eoe_timeout - set the end of event timeout to given value * * Args * new_eoe_tmo - value * Rtn * void */ void lol_set_eoe_timeout(time_t new_eoe_tmo) { eoe_timeout = new_eoe_tmo; } time_t lol_get_eoe_timeout(void) { return eoe_timeout; } audit-userspace-4.0.5/src/ausearch-lol.h000066400000000000000000000034051501761310600201370ustar00rootroot00000000000000/* * ausearch-lol.h - linked list of linked lists library header * Copyright (c) 2008 Red Hat Inc., Durham, North Carolina. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUSEARCH_LOL_HEADER #define AUSEARCH_LOL_HEADER #include "config.h" #include "ausearch-llist.h" typedef enum { L_EMPTY, L_BUILDING, L_COMPLETE } lol_t; /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _lolnode{ llist *l; // The linked list int status; // 0 = empty, 1 in use, 2 complete } lolnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { lolnode *array; int maxi; // Largest index used int limit; // Number of nodes in the array } lol; void lol_create(lol *lo); void lol_clear(lol *lo); int lol_add_record(lol *lo, char *buff); void terminate_all_events(lol *lo); void complete_all_events(lol *lo); llist* get_ready_event(lol *lo); void lol_set_eoe_timeout(time_t new_eoe_tmo); #endif audit-userspace-4.0.5/src/ausearch-lookup.c000066400000000000000000000304331501761310600206560ustar00rootroot00000000000000/* * ausearch-lookup.c - Lookup values to something more readable * Copyright (c) 2005-06,2011-12,2015-17 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include #include #include #include #include "ausearch-lookup.h" #include "ausearch-options.h" #include "ausearch-nvpair.h" #include "auparse-idata.h" /* This is the name/value pair used by search tables */ struct nv_pair { int value; const char *name; }; /* The machine based on elf type */ static int machine = 0; static const char *Q = "?"; static const char *results[3]= { "unset", "denied", "granted" }; static const char *success[3]= { "unset", "no", "yes" }; static const char *aulookup_socketcall(long sc); static const char *aulookup_ipccall(long ic); const char *aulookup_result(avc_t result) { return results[result]; } const char *aulookup_success(int s) { switch (s) { default: return success[0]; break; case S_FAILED: return success[1]; break; case S_SUCCESS: return success[2]; break; } } const char *aulookup_syscall(llist *l, char *buf, size_t size) { const char *sys; if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", l->s.syscall); return buf; } sys = _auparse_lookup_interpretation("syscall"); if (sys) { snprintf(buf, size, "%s", sys); free((void *)sys); return buf; } machine = audit_elf_to_machine(l->s.arch); if (machine < 0) return Q; sys = audit_syscall_to_name(l->s.syscall, machine); if (sys) { const char *func = NULL; if (strcmp(sys, "socketcall") == 0) { if (list_find_item(l, AUDIT_SYSCALL)) func = aulookup_socketcall((long)l->cur->a0); } else if (strcmp(sys, "ipc") == 0) { if(list_find_item(l, AUDIT_SYSCALL)) func = aulookup_ipccall((long)l->cur->a0); } if (func) { snprintf(buf, size, "%s(%s)", sys, func); return buf; } snprintf(buf, size, "%s", sys); return buf; } snprintf(buf, size, "%d", l->s.syscall); return buf; } // See include/linux/net.h static const struct nv_pair socktab[] = { {SYS_SOCKET, "socket"}, {SYS_BIND, "bind"}, {SYS_CONNECT, "connect"}, {SYS_LISTEN, "listen"}, {SYS_ACCEPT, "accept"}, {SYS_GETSOCKNAME, "getsockname"}, {SYS_GETPEERNAME, "getpeername"}, {SYS_SOCKETPAIR, "socketpair"}, {SYS_SEND, "send"}, {SYS_RECV, "recv"}, {SYS_SENDTO, "sendto"}, {SYS_RECVFROM, "recvfrom"}, {SYS_SHUTDOWN, "shutdown"}, {SYS_SETSOCKOPT, "setsockopt"}, {SYS_GETSOCKOPT, "getsockopt"}, {SYS_SENDMSG, "sendmsg"}, {SYS_RECVMSG, "recvmsg"}, {SYS_ACCEPT4, "accept4"}, {19, "recvmmsg"}, {20, "sendmmsg"} }; #define SOCK_NAMES (sizeof(socktab)/sizeof(socktab[0])) static const char *aulookup_socketcall(long sc) { unsigned int i; for (i = 0; i < SOCK_NAMES; i++) if (socktab[i].value == sc) return socktab[i].name; return NULL; } /* This is from asm/ipc.h. Copying it for now as some platforms * have broken headers. */ #define SEMOP 1 #define SEMGET 2 #define SEMCTL 3 #define SEMTIMEDOP 4 #define MSGSND 11 #define MSGRCV 12 #define MSGGET 13 #define MSGCTL 14 #define SHMAT 21 #define SHMDT 22 #define SHMGET 23 #define SHMCTL 24 /* * This table maps ipc calls to their text name */ static const struct nv_pair ipctab[] = { {SEMOP, "semop"}, {SEMGET, "semget"}, {SEMCTL, "semctl"}, {SEMTIMEDOP, "semtimedop"}, {MSGSND, "msgsnd"}, {MSGRCV, "msgrcv"}, {MSGGET, "msgget"}, {MSGCTL, "msgctl"}, {SHMAT, "shmat"}, {SHMDT, "shmdt"}, {SHMGET, "shmget"}, {SHMCTL, "shmctl"} }; #define IPC_NAMES (sizeof(ipctab)/sizeof(ipctab[0])) static const char *aulookup_ipccall(long ic) { unsigned int i; for (i = 0; i < IPC_NAMES; i++) if (ipctab[i].value == ic) return ipctab[i].name; return NULL; } static nvlist uid_nvl; static int uid_list_created=0; const char *aulookup_uid(uid_t uid, char *buf, size_t size) { const char *name; int rc; if (report_format <= RPT_DEFAULT) { snprintf(buf, size, "%d", uid); return buf; } if (uid == -1) { snprintf(buf, size, "unset"); return buf; } name = _auparse_lookup_interpretation("auid"); if (name) { snprintf(buf, size, "%s", name); free((void *)name); return buf; } // Check the cache first if (uid_list_created == 0) { search_list_create(&uid_nvl); search_list_clear(&uid_nvl); uid_list_created = 1; } rc = search_list_find_val(&uid_nvl, uid); if (rc) { name = uid_nvl.cur->name; } else { // This getpw use is OK because its for protocol 1 compatibility // Add it to cache struct passwd *pw; pw = getpwuid(uid); if (pw) { nvnode nv; nv.name = strdup(pw->pw_name); nv.val = uid; search_list_append(&uid_nvl, &nv); name = uid_nvl.cur->name; } } if (name != NULL) snprintf(buf, size, "%s", name); else snprintf(buf, size, "unknown(%d)", uid); return buf; } void aulookup_destroy_uid_list(void) { if (uid_list_created == 0) return; search_list_clear(&uid_nvl); uid_list_created = 0; } static int is_hex_string(const char *str) { while (*str) { if (!isxdigit(*str)) return 0; str++; } return 1; } /* * This function will take a pointer to a 2 byte Ascii character buffer and * return the actual hex value. */ static unsigned char x2c(unsigned char *buf) { static const char AsciiArray[17] = "0123456789ABCDEF"; char *ptr; unsigned char total=0; ptr = strchr(AsciiArray, (char)toupper(buf[0])); if (ptr) total = (unsigned char)(((ptr-AsciiArray) & 0x0F)<<4); ptr = strchr(AsciiArray, (char)toupper(buf[1])); if (ptr) total += (unsigned char)((ptr-AsciiArray) & 0x0F); return total; } /* returns a freshly malloc'ed and converted buffer */ char *unescape(const char *buf) { int len, i; char *str, *strptr; const char *ptr = buf; /* Find the end of the name */ if (*ptr == '(') { ptr = strchr(ptr, ')'); if (ptr == NULL) return NULL; else ptr++; } else { while (isxdigit(*ptr)) ptr++; } if ((ptr - buf) == 0) return NULL; str = strndup(buf, ptr - buf); if (str == NULL) { fprintf(stderr, "Out of memory. Check %s file, %d line", __FILE__, __LINE__); return NULL; } if (*buf == '(') return str; /* We can get away with this since the buffer is 2 times * bigger than what we are putting there. */ len = strlen(str); if (len < 2) { free(str); return NULL; } strptr = str; for (i=0; i> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else putchar(s[i]); i++; } } static const char sh_set[] = "\"'`$\\!()| "; static unsigned int need_shell_escape(const char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(sh_set, s[i])) cnt++; i++; } return cnt; } static void shell_escape(const char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if ((unsigned char)s[i] < 32) { putchar('\\'); putchar('0' + ((s[i] & 0300) >> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else if (strchr(sh_set, s[i])) { putchar('\\'); putchar(s[i]); } else putchar(s[i]); i++; } } static const char quote_set[] = "\"'`$\\!()| ;#&*?[]<>{}"; static unsigned int need_shell_quote_escape(const unsigned char *s, unsigned int len) { unsigned int i = 0, cnt = 0; while (i < len) { if (s[i] < 32) cnt++; else if (strchr(quote_set, s[i])) cnt++; i++; } return cnt; } static void shell_quote_escape(const char *s, unsigned int len) { unsigned int i = 0; while (i < len) { if ((unsigned char)s[i] < 32) { putchar('\\'); putchar('0' + ((s[i] & 0300) >> 6)); putchar('0' + ((s[i] & 0070) >> 3)); putchar('0' + (s[i] & 0007)); } else if (strchr(quote_set, s[i])) { putchar('\\'); putchar(s[i]); } else putchar(s[i]); i++; } } static unsigned int need_escaping(const char *s, unsigned int len) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: return need_tty_escape(s, len); case AUPARSE_ESC_SHELL: return need_shell_escape(s, len); case AUPARSE_ESC_SHELL_QUOTE: return need_shell_quote_escape(s, len); } return 0; } static void escape(const char *s, unsigned int len) { switch (escape_mode) { case AUPARSE_ESC_RAW: break; case AUPARSE_ESC_TTY: tty_escape(s, len); break; case AUPARSE_ESC_SHELL: shell_escape(s, len); break; case AUPARSE_ESC_SHELL_QUOTE: shell_quote_escape(s, len); break; } } void safe_print_string_n(const char *s, unsigned int len, int ret) { if (len > MAX_AUDIT_MESSAGE_LENGTH) len = MAX_AUDIT_MESSAGE_LENGTH; if (need_escaping(s, len)) { escape(s, len); if (ret) putchar('\n'); } else if (ret) puts(s); else printf("%s", s); } void safe_print_string(const char *s, int ret) { if (s == NULL) fputs("(null)", stdout); else safe_print_string_n(s, strlen(s), ret); } /* Represent c as a character within a quoted string, and append it to buf. */ static void tty_printable_char(unsigned char c) { if (c < 0x20 || c > 0x7E) { putchar('\\'); putchar('0' + ((c >> 6) & 07)); putchar('0' + ((c >> 3) & 07)); putchar('0' + (c & 07)); } else { if (c == '\\' || c == '"') putchar('\\'); putchar(c); } } /* Search for a name of a sequence of TTY bytes. * If found, return the name and advance *INPUT. * Return NULL otherwise. */ static const char *tty_find_named_key(unsigned char **input, size_t input_len) { /* NUL-terminated list of (sequence, NUL, name, NUL) entries. First match wins, even if a longer match were possible later */ static const unsigned char named_keys[] = #define E(SEQ, NAME) SEQ "\0" NAME "\0" #include "auparse/tty_named_keys.h" #undef E "\0"; unsigned char *src; const unsigned char *nk; src = *input; if (*src >= ' ' && (*src < 0x7F || *src >= 0xA0)) return NULL; /* Fast path */ nk = named_keys; do { const unsigned char *p; size_t nk_len; p = strchr((const char *)nk, '\0'); nk_len = p - nk; if (nk_len <= input_len && memcmp(src, nk, nk_len) == 0) { *input += nk_len; return (const char *)(p + 1); } nk = strchr((const char *)p + 1, '\0') + 1; } while (*nk != '\0'); return NULL; } void print_tty_data(const char *val) { int need_comma, in_printable = 0; unsigned char *data, *data_pos, *data_end; if (!is_hex_string(val)) { printf("%s", val); return; } if ((data = unescape((char *)val)) == NULL) { printf("conversion error(%s)", val); return; } data_end = data + strlen(val) / 2; data_pos = data; need_comma = 0; while (data_pos < data_end) { /* FIXME: Unicode */ const char *desc; desc = tty_find_named_key(&data_pos, data_end - data_pos); if (desc != NULL) { if (in_printable != 0) { putchar('"'); in_printable = 0; } if (need_comma != 0) putchar(','); printf("<%s>", desc); } else { if (in_printable == 0) { if (need_comma != 0) putchar(','); putchar('"'); in_printable = 1; } tty_printable_char(*data_pos); data_pos++; } need_comma = 1; } if (in_printable != 0) putchar('"'); free(data); } audit-userspace-4.0.5/src/ausearch-lookup.h000066400000000000000000000031011501761310600206530ustar00rootroot00000000000000/* * ausearch-lookup.h - Header file for ausearch-lookup.c * Copyright (c) 2005-06,2014,2017,2022 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AULOOKUP_HEADER #define AULOOKUP_HEADER #include "config.h" #include #include #include "libaudit.h" #include "ausearch-llist.h" const char *aulookup_result(avc_t result); const char *aulookup_success(int s); const char *aulookup_syscall(llist *l, char *buf, size_t size) __attr_access ((__write_only__, 2, 3)); const char *aulookup_uid(uid_t uid, char *buf, size_t size) __attr_access ((__write_only__, 2, 3)); void aulookup_destroy_uid_list(void); char *unescape(const char *buf); void print_tty_data(const char *val); void safe_print_string_n(const char *s, unsigned int len, int ret) __attr_access ((__read_only__, 1, 2)); void safe_print_string(const char *s, int ret); #endif audit-userspace-4.0.5/src/ausearch-match.c000066400000000000000000000233411501761310600204410ustar00rootroot00000000000000/* * ausearch-match.c - Extract interesting fields and check for match * Copyright (c) 2005-08, 2011 Red Hat Inc. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb * Marcelo Henrique Cerri */ #include "config.h" #include #include "libaudit.h" #include "ausearch-options.h" #include "ausearch-parse.h" extern void ausearch_load_interpretations(const lnode *n); /* local functions */ static int strmatch(const char *needle, const char *haystack); static int user_match(llist *l); static int group_match(llist *l); static int context_match(llist *l); static void load_interpretations(const llist *l) { // See if there is any reason to load interpretations if (event_tuid == NULL && event_teuid == NULL && event_tauid == NULL) return; // If there is only 1 record load it, or load just the syscall one if ((l->cnt == 1) || (l->head && l->head->type == AUDIT_SYSCALL)) ausearch_load_interpretations(l->head); } /* * This function performs that matching of search params with the record. * It returns 1 on a match, and 0 if no match. The way that this function * works is that it will try to determine if there is not a match and exit * as soon as possible. We can do this since all command line params form * an 'and' statement. If anything does not match, no need to evaluate the * rest of the params. */ #include int match(llist *l) { // Are we within time range? if (start_time == 0 || l->e.sec >= start_time) { if (end_time == 0 || l->e.sec <= end_time) { if (event_id == -1 || event_id == l->e.serial) { // Load interpretations if needed load_interpretations(l); // OK - do the heavier checking if (extract_search_items(l)) { return 0; } // perform additional tests for the field if (event_node_list) { const snode *sn; int found=0; slist *sptr = event_node_list; if (l->e.node == NULL) return 0; slist_first(sptr); sn=slist_get_cur(sptr); while (sn && !found) { if (sn->str && (!strcmp(sn->str, l->e.node))) found++; else sn=slist_next(sptr); } if (!found) return 0; } if (user_match(l) == 0) return 0; if (group_match(l) == 0) return 0; if ((event_ppid != -1) && (event_ppid != l->s.ppid)) return 0; if ((event_pid != -1) && (event_pid != l->s.pid)) return 0; if (event_machine != -1 && (event_machine != audit_elf_to_machine(l->s.arch))) return 0; if ((event_syscall != -1) && (event_syscall != l->s.syscall)) return 0; if ((event_session_id != -2) && (event_session_id != l->s.session_id)) return 0; if (event_exit_is_set) { if (l->s.exit_is_set == 0) return 0; if (event_exit != l->s.exit) return 0; } if ((event_success != S_UNSET) && (event_success != l->s.success)) return 0; // event_type requires looking at each item if (event_type != NULL) { int found = 0; const lnode *n; list_first(l); n = list_get_cur(l); do { int_node *in; ilist_first(event_type); in = ilist_get_cur(event_type); do { if (in->num == n->type){ found = 1; break; } } while((in = ilist_next(event_type))); if (found) break; } while ((n = list_next(l))); if (!found) return 0; } // Done all the easy compares, now do the // string searches. if (event_filename) { int found = 0; if (l->s.filename == NULL && l->s.cwd == NULL) return 0; if (l->s.filename) { const snode *sn; slist *sptr = l->s.filename; slist_first(sptr); sn=slist_get_cur(sptr); do { if (sn->str == NULL) return 0; if (strmatch( event_filename, sn->str)) { found = 1; break; } } while ((sn=slist_next(sptr))); if (!found && l->s.cwd == NULL) return 0; } if (l->s.cwd && !found) { /* Check cwd, too */ if (strmatch(event_filename, l->s.cwd) == 0) return 0; } } if (event_hostname) { if (l->s.hostname == NULL) return 0; if (strmatch(event_hostname, l->s.hostname) == 0) return 0; } if (event_terminal) { if (l->s.terminal == NULL) return 0; if (strmatch(event_terminal, l->s.terminal) == 0) return 0; } if (event_exe) { if (l->s.exe == NULL) return 0; if (strmatch(event_exe, l->s.exe) == 0) return 0; } if (event_comm) { if (l->s.comm == NULL) return 0; if (strmatch(event_comm, l->s.comm) == 0) return 0; } if (event_key) { if (l->s.key == NULL) return 0; else { int found = 0; const snode *sn; slist *sptr = l->s.key; slist_first(sptr); sn=slist_get_cur(sptr); do { if (sn->str == NULL) return 0; if (strmatch( event_key, sn->str)) { found = 1; break; } } while ((sn=slist_next(sptr))); if (!found) return 0; } } if (event_vmname) { if (l->s.vmname == NULL) return 0; if (strmatch(event_vmname, l->s.vmname) == 0) return 0; } if (event_uuid) { if (l->s.uuid == NULL) return 0; if (strmatch(event_uuid, l->s.uuid) == 0) return 0; } if (context_match(l) == 0) return 0; return 1; } } } return 0; } /* * This function compares strings. It returns a 0 if no match and a 1 if * there is a match */ static int strmatch(const char *needle, const char *haystack) { if (event_exact_match) { if (strcmp(haystack, needle) != 0) return 0; } else { if (strstr(haystack, needle) == NULL) return 0; } return 1; } /* * This function compares user id's. * It returns a 0 if no match and a 1 if there is a match */ static int user_match(llist *l) { // Match by string if set (assume all event vars are set) if (event_ua && event_tuid) { // This will "or" the user tests if (l->s.tuid && strcmp(event_tuid, l->s.tuid) == 0) return 1; if (l->s.teuid && strcmp(event_teuid, l->s.teuid) == 0) return 1; if (l->s.tauid && strcmp(event_tauid, l->s.tauid) == 0) return 1; return 0; // OK, try a pure numeric match } else if (event_ua) { // This will "or" the user tests if (event_uid == l->s.uid) return 1; if (event_euid == l->s.euid) return 1; if (event_loginuid == l->s.loginuid) return 1; return 0; } else { // This will "and" the user tests if (event_tuid || event_teuid || event_tauid) { if (event_tuid) { if (l->s.tuid == NULL) return 0; if (strcmp(event_tuid, l->s.tuid)) return 0; } if (event_teuid) { if (l->s.teuid == NULL) return 0; if (strcmp(event_teuid, l->s.teuid)) return 0; } if (event_tauid) { if (l->s.tauid == NULL) return 0; if (strcmp(event_tauid, l->s.tauid)) return 0; } } else { // Numeric only match if ((event_uid != -1) && (event_uid != l->s.uid)) return 0; if ((event_euid != -1) &&(event_euid != l->s.euid)) return 0; if ((event_loginuid != -2) && (event_loginuid != l->s.loginuid)) return 0; } } return 1; } /* * This function compares group id's. It returns a 0 if no match and a 1 if * there is a match */ static int group_match(llist *l) { if (event_ga) { // This will "or" the group tests if (event_gid == l->s.gid) return 1; if (event_egid == l->s.egid) return 1; return 0; } else { // This will "and" the group tests if ((event_gid != -1) && (event_gid != l->s.gid)) return 0; if ((event_egid != -1) &&(event_egid != l->s.egid)) return 0; } return 1; } /* * This function compares contexts. It returns a 0 if no match and a 1 if * there is a match */ static int context_match(llist *l) { if (event_se) { /* This does the "or" check if -se test */ if (event_subject) { if (l->s.avc && alist_find_subj(l->s.avc)) { do { if (strmatch(event_subject, l->s.avc->cur->scontext)) return 1; } while(alist_next_subj(l->s.avc)); } } if (event_object) { if (l->s.avc) { alist_first(l->s.avc); if (alist_find_obj(l->s.avc)) { do { if (strmatch(event_object, l->s.avc->cur->tcontext)) return 1; } while(alist_next_obj(l->s.avc)); } } } return 0; } else { /* This is an 'and' requiring both to match */ int found = 0; if (event_subject) { if (l->s.avc == NULL) return 0; if (alist_find_subj(l->s.avc)) { do { if (strmatch(event_subject, l->s.avc->cur->scontext)) found = 1; } while(alist_next_subj(l->s.avc)); } if (!found) return 0; } found = 0; if (event_object) { if (l->s.avc == NULL) return 0; if (alist_find_obj(l->s.avc)) { do { if (strmatch(event_object, l->s.avc->cur->tcontext)) found = 1; } while(alist_next_obj(l->s.avc)); } if (!found) return 0; } } return 1; } audit-userspace-4.0.5/src/ausearch-nvpair.c000066400000000000000000000037441501761310600206510ustar00rootroot00000000000000/* * ausearch-nvpair.c - Minimal linked list library for name-value pairs * Copyright (c) 2006-08 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #include "config.h" #include #include "ausearch-nvpair.h" void search_list_create(nvlist *l) { l->head = NULL; l->cur = NULL; l->cnt = 0; } int search_list_append(nvlist *l, nvnode *node) { nvnode* newnode = malloc(sizeof(nvnode)); if (newnode == NULL) return 1; newnode->name = node->name; newnode->val = node->val; newnode->next = NULL; // if we are at top, fix this up if (l->head == NULL) l->head = newnode; else { // Add pointer to newnode and make sure we are at the end while (l->cur->next) l->cur = l->cur->next; l->cur->next = newnode; } // make newnode current l->cur = newnode; l->cnt++; return 0; } int search_list_find_val(nvlist *l, long val) { register nvnode* node = l->head; while (node) { if (node->val == val) { l->cur = node; return 1; } else node = node->next; } return 0; } void search_list_clear(nvlist* l) { nvnode* nextnode; register nvnode* current; current = l->head; while (current) { nextnode=current->next; free(current->name); free(current); current=nextnode; } l->head = NULL; l->cur = NULL; l->cnt = 0; } audit-userspace-4.0.5/src/ausearch-nvpair.h000066400000000000000000000034121501761310600206460ustar00rootroot00000000000000/* * ausearch-nvpair.h - Header file for ausearch-nvpair.c * Copyright (c) 2006-08 Red Hat Inc. * All Rights Reserved. * * This software may be freely redistributed and/or modified under the * terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor * Boston, MA 02110-1335, USA. * * Authors: * Steve Grubb */ #ifndef AUNVPAIR_HEADER #define AUNVPAIR_HEADER #include "config.h" #include /* This is the node of the linked list. message & item are the only elements * at this time. Any data elements that are per item goes here. */ typedef struct _nvnode{ char *name; // The name string long val; // The value field struct _nvnode* next; // Next nvpair node pointer } nvnode; /* This is the linked list head. Only data elements that are 1 per * event goes here. */ typedef struct { nvnode *head; // List head nvnode *cur; // Pointer to current node unsigned int cnt; // How many items in this list } nvlist; void search_list_create(nvlist *l); static inline nvnode *search_list_get_cur(nvlist *l) { return l->cur; } int search_list_append(nvlist *l, nvnode *node); void search_list_clear(nvlist* l); /* Given a numeric index, find that record. */ int search_list_find_val(nvlist *l, long val); #endif audit-userspace-4.0.5/src/ausearch-options.c000066400000000000000000000776021501761310600210510ustar00rootroot00000000000000/* ausearch-options.c - parse commandline options and configure ausearch * Copyright 2005-08,2010-11,2014,2016-17 Red Hat Inc., Durham, North Carolina. * Copyright (c) 2011 IBM Corp. * All Rights Reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Authors: * Debora Velarde * Steve Grubb * Marcelo Henrique Cerri */ #include "config.h" #include #include #include #include #include #include #include #include #include "ausearch-options.h" #include "ausearch-time.h" #include "ausearch-int.h" #include "libaudit.h" #include "auparse-defs.h" /* Global vars that will be accessed by the main program */ char *user_file = NULL; int force_logs = 0; const char *checkpt_filename = NULL; /* checkpoint filename if present */ report_t report_format = RPT_DEFAULT; /* Global vars that will be accessed by the match model */ unsigned int event_id = -1; gid_t event_gid = -1, event_egid = -1; ilist *event_type = NULL; pid_t event_pid = -1, event_ppid = -1; success_t event_success = S_UNSET; auparse_esc_t escape_mode = AUPARSE_ESC_TTY; int event_exact_match = 0; uid_t event_uid = -1, event_euid = -1, event_loginuid = -2; const char *event_tuid = NULL, *event_teuid = NULL, *event_tauid = NULL; int event_syscall = -1, event_machine = -1; int event_ua = 0, event_ga = 0, event_se = 0; int just_one = 0; uint32_t event_session_id = -2; long long event_exit = 0; int event_exit_is_set = 0; int line_buffered = 0; int event_debug = 0; int checkpt_timeonly = 0; int extra_keys = 0, extra_labels = 0, extra_obj2 = 0, extra_time = 0; const char *event_key = NULL; const char *event_filename = NULL; const char *event_exe = NULL; const char *event_comm = NULL; const char *event_hostname = NULL; const char *event_terminal = NULL; const char *event_subject = NULL; const char *event_object = NULL; const char *event_uuid = NULL; const char *event_vmname = NULL; ilist *event_type; time_t arg_eoe_timeout = (time_t)0; slist *event_node_list = NULL; struct nv_pair { int value; const char *name; }; enum { S_EVENT, S_COMM, S_FILENAME, S_ALL_GID, S_EFF_GID, S_GID, S_HELP, S_HOSTNAME, S_INTERP, S_INFILE, S_MESSAGE_TYPE, S_PID, S_SYSCALL, S_OSUCCESS, S_TIME_END, S_TIME_START, S_TERMINAL, S_ALL_UID, S_EFF_UID, S_UID, S_LOGINID, S_VERSION, S_EXACT_MATCH, S_EXECUTABLE, S_CONTEXT, S_SUBJECT, S_OBJECT, S_PPID, S_KEY, S_RAW, S_NODE, S_IN_LOGS, S_JUST_ONE, S_SESSION, S_EXIT, S_LINEBUFFERED, S_UUID, S_VMNAME, S_DEBUG, S_CHECKPOINT, S_ARCH, S_FORMAT, S_EXTRA_TIME, S_EXTRA_LABELS, S_EXTRA_KEYS, S_EXTRA_OBJ2, S_ESCAPE, S_EOE_TMO }; static const struct nv_pair optiontab[] = { { S_EVENT, "-a" }, { S_ARCH, "--arch" }, { S_EVENT, "--event" }, { S_COMM, "-c" }, { S_COMM, "--comm" }, { S_CHECKPOINT, "--checkpoint" }, { S_DEBUG, "--debug" }, { S_EXIT, "-e" }, { S_EOE_TMO, "--eoe-timeout" }, { S_ESCAPE, "--escape" }, { S_EXIT, "--exit" }, { S_EXTRA_KEYS, "--extra-keys" }, { S_EXTRA_LABELS, "--extra-labels" }, { S_EXTRA_OBJ2, "--extra-obj2" }, { S_EXTRA_TIME, "--extra-time" }, { S_FILENAME, "-f" }, { S_FILENAME, "--file" }, { S_FORMAT, "--format" }, { S_ALL_GID, "-ga" }, { S_ALL_GID, "--gid-all" }, { S_EFF_GID, "-ge" }, { S_EFF_GID, "--gid-effective" }, { S_GID, "-gi" }, { S_GID, "--gid" }, { S_HELP, "-h" }, { S_HELP, "--help" }, { S_HOSTNAME, "-hn" }, { S_HOSTNAME, "--host" }, { S_INTERP, "-i" }, { S_INTERP, "--interpret" }, { S_INFILE, "-if" }, { S_INFILE, "--input" }, { S_IN_LOGS, "--input-logs" }, { S_JUST_ONE, "--just-one" }, { S_KEY, "-k" }, { S_KEY, "--key" }, { S_LINEBUFFERED, "-l" }, { S_LINEBUFFERED, "--line-buffered" }, { S_MESSAGE_TYPE, "-m" }, { S_MESSAGE_TYPE, "--message" }, { S_NODE, "-n" }, { S_NODE, "--node" }, { S_OBJECT, "-o" }, { S_OBJECT, "--object" }, { S_PID, "-p" }, { S_PID, "--pid" }, { S_PPID, "-pp" }, { S_PPID, "--ppid" }, { S_RAW, "-r" }, { S_RAW, "--raw" }, { S_SYSCALL, "-sc" }, { S_SYSCALL, "--syscall" }, { S_CONTEXT, "-se" }, { S_CONTEXT, "--context" }, { S_SESSION, "--session" }, { S_SUBJECT, "-su" }, { S_SUBJECT, "--subject" }, { S_OSUCCESS, "-sv" }, { S_OSUCCESS, "--success" }, { S_TIME_END, "-te"}, { S_TIME_END, "--end"}, { S_TIME_START, "-ts" }, { S_TIME_START, "--start" }, { S_TERMINAL, "-tm" }, { S_TERMINAL, "--terminal" }, { S_ALL_UID, "-ua" }, { S_ALL_UID, "--uid-all" }, { S_EFF_UID, "-ue" }, { S_EFF_UID, "--uid-effective" }, { S_UID, "-ui" }, { S_UID, "--uid" }, { S_UUID, "-uu" }, { S_UUID, "--uuid" }, { S_LOGINID, "-ul" }, { S_LOGINID, "--loginuid" }, { S_VERSION, "-v" }, { S_VERSION, "--version" }, { S_VMNAME, "-vm" }, { S_VMNAME, "--vm-name" }, { S_EXACT_MATCH, "-w" }, { S_EXACT_MATCH, "--word" }, { S_EXECUTABLE, "-x" }, { S_EXECUTABLE, "--executable" } }; #define OPTION_NAMES (sizeof(optiontab)/sizeof(optiontab[0])) static int audit_lookup_option(const char *name) { unsigned int i; for (i = 0; i < OPTION_NAMES; i++) if (!strcmp(optiontab[i].name, name)) return optiontab[i].value; return -1; } static void usage(void) { printf("usage: ausearch [options]\n" "\t-a,--event \tsearch based on audit event id\n" "\t--arch \t\t\tsearch based on the CPU architecture\n" "\t-c,--comm \t\tsearch based on command line name\n" "\t--checkpoint \tsearch from last complete event\n" "\t--debug\t\t\tWrite malformed events that are skipped to stderr\n" "\t-e,--exit \tsearch based on syscall exit code\n" "\t-escape