pax_global_header00006660000000000000000000000064143500430500014504gustar00rootroot0000000000000052 comment=3139466a38cd204e34c32cdeb106d6cb309f1025 usbguard-notifier-0.1.0/000077500000000000000000000000001435004305000151335ustar00rootroot00000000000000usbguard-notifier-0.1.0/.github/000077500000000000000000000000001435004305000164735ustar00rootroot00000000000000usbguard-notifier-0.1.0/.github/workflows/000077500000000000000000000000001435004305000205305ustar00rootroot00000000000000usbguard-notifier-0.1.0/.github/workflows/build.yml000066400000000000000000000030431435004305000223520ustar00rootroot00000000000000name: C/C++ CI on: push: branches: [ master, CI ] pull_request: branches: [ master ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: install dependencies for usbguard run: | sudo apt-get -qq update sudo apt-get install -y libudev-dev libsodium-dev libqb-dev libcap-ng-dev libseccomp-dev sudo apt-get install -y libglib2.0-dev libdbus-glib-1-dev libxml2-utils libpolkit-gobject-1-dev xsltproc sudo apt-get install -y libprotobuf-dev protobuf-compiler sudo apt-get install -y asciidoc docbook-xml docbook-xsl sudo apt-get install -y umockdev libumockdev-dev sudo apt-get install -y gcc g++ sudo apt-get install -y libgcrypt-dev - name: build usbguard run: | git clone https://github.com/USBGuard/usbguard.git pushd usbguard ./autogen.sh CC=gcc CXX=g++ ./configure --with-bundled-catch --with-bundled-pegtl --with-crypto-library=gcrypt make popd - name: install dependencies for usbguard-notifier run: | sudo apt-get -qq update sudo apt-get install -y librsvg2-dev libnotify-dev autoconf automake libtool make g++ asciidoc git - name: build usbguard-notifier run: | ./autogen.sh ./configure --disable-silent-rules --with-bundled-catch --disable-notifier-cli --prefix /home/$(id -un) --with-usbguard-devel="./usbguard" make make install SYSTEMD_UNIT_DIR=/home/$(id -un)/.config/systemd/user/ make dist usbguard-notifier-0.1.0/.gitignore000066400000000000000000000007531435004305000171300ustar00rootroot00000000000000# autoconf & automake aclocal.m4 autom4te.cache config/ configure config.log config.status Makefile.in Makefile .deps m4 .dirstamp libtool # executables usbguard-notifier usbguard-notifier-cli # protobuf generated files *.pb.cc *.pb.h # Compiled object files *.slo *.lo *.o *.obj # sysmted usbguard-notifier.service # doc, man man/usbguard-notifier.1 man/usbguard-notifier-cli.1 # tests test-unit src/Tests/*.log src/Tests/*.trs # others src/BuildConfig.h usbguard-notifier.conf tags usbguard-notifier-0.1.0/.gitmodules000066400000000000000000000001601435004305000173050ustar00rootroot00000000000000[submodule "src/ThirdParty/Catch2"] path = src/ThirdParty/Catch2 url = https://github.com/catchorg/Catch2.git usbguard-notifier-0.1.0/.travis.yml000066400000000000000000000006521435004305000172470ustar00rootroot00000000000000language: cpp services: - docker before_install: - docker pull fedora:32 script: - > docker run -v $TRAVIS_BUILD_DIR/:/root/build/ fedora:32 /bin/sh -c "cd /root/build; dnf install --nogpgcheck -y librsvg2-devel libnotify-devel usbguard-devel autoconf automake libtool make gcc-c++ asciidoc git && ./autogen.sh && ./configure --prefix /home/$(id -un) --with-bundled-catch && make" usbguard-notifier-0.1.0/CHANGELOG.md000066400000000000000000000034111435004305000167430ustar00rootroot00000000000000### 0.1.0 - 2022-12-19 ## Added - Add "--with-usbguard-devel" configuration option to compile with usbguard-devel source files. - Merge notifications when inserting devices. This reduces the amount of notifications by 1 when inserting a device, which is allowed by the policy. - Introduce action buttons to allow or reject devices from notifications. ## Fixed - Decrease spam when IPC connection fails. In case connection through the IPC can not be established, do not produce unnecessary warning messages. - Change the injection of the usbguard-icon. - Update Catch2 submodule to the latest stable 2.x. ### 0.0.6 - 2020-04-29 ## Added - Configuration option that disables building notifier-cli ## Fixed - Fix segmentation fault when login can not be determined ## Removed - Remove unnecessary dependency(libqb>=1.0.5), which does not exist in some distributions yet. We do not use libqb directly, so we let usbguard decide which version they do want as a requirement. ### 0.0.5 - 2020-03-02 ## Added - Pass FLAGS to configure script ### 0.0.4 - 2020-02-24 ## Added - Configuration file now has an additional option to use either systemd-system-unitdir or systemd-user-unitdir ### 0.0.3 - 2020-02-14 ## Fixed - Configure.ac has been updated to ensure that a recent version of Autoconf is being used - Added missing dependencies to the documentation ### 0.0.2 - 2019-12-12 ## Added - There is no need to restart Notifier in case Usbguard stops working. - Debug option in configure script ## Fixed - Temporary notifications path can be set at the configuration phase - README.md update - Debug information when the connection is established successfully ## Removed - Unnecessary dependencies have been removed from configuration ### 0.0.1 - 2019-11-07 - Initial pre-release usbguard-notifier-0.1.0/LICENSE000066400000000000000000000432541435004305000161500ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. usbguard-notifier-0.1.0/Makefile.am000066400000000000000000000070551435004305000171760ustar00rootroot00000000000000## ## Copyright (C) 2019 Red Hat, Inc. ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, 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, see . ## ## Author(s): Attila Lakatos ## ACLOCAL_AMFLAGS = -I m4 CLEANFILES = SUBDIRS = src/Tests/ bin_PROGRAMS = usbguard-notifier if NOTIFIER_CLI_ENABLED bin_PROGRAMS += \ usbguard-notifier-cli endif EXTRA_DIST = \ src/BuildConfig.h.in \ README.md \ LICENSE \ CHANGELOG.md \ src/ThirdParty/Catch2/single_include/catch2 usbguard_notifier_SOURCES = \ src/usbguard-icon.hpp \ src/Notifier.hpp \ src/NotifyWrapper.hpp \ src/Serializer.hpp \ src/Log.hpp \ src/Main.cpp \ src/Notifier.cpp \ src/NotifyWrapper.cpp \ src/Serializer.cpp \ src/Log.cpp usbguard_notifier_LDFLAGS = \ @rsvg_LIBS@ \ @notify_LIBS@ \ @usbguard_LIBS@ usbguard_notifier_CXXFLAGS = \ @rsvg_CFLAGS@ \ @notify_CFLAGS@ \ @usbguard_CFLAGS@ \ -fPIC if CUSTOM_USBGUARD_DEVEL_ENABLED usbguard_notifier_LDADD = \ @usbguard_LA@ usbguard_notifier_cli_LDADD = \ @usbguard_LA@ endif BUILT_SOURCES = \ src/BuildConfig.h \ src/usbguard-icon.hpp usbguard_notifier_cli_SOURCES = \ src/Serializer.hpp \ src/NotifierCLI.hpp \ src/Serializer.cpp \ src/NotifierCLI.cpp \ src/MainCli.cpp usbguard_notifier_cli_LDFLAGS = \ @usbguard_LIBS@ usbguard_notifier_cli_CXXFLAGS = \ @usbguard_CFLAGS@ \ -fPIC # # manual pages # SUFFIXES = .adoc man_ADOC_FILES = \ $(top_builddir)/man/usbguard-notifier.1 if NOTIFIER_CLI_ENABLED man_ADOC_FILES += \ $(top_builddir)/man/usbguard-notifier-cli.1 endif .adoc: $(A2X) -f manpage $^ man1_MANS = \ $(man_ADOC_FILES) CLEANFILES += \ $(man_ADOC_FILES) EXTRA_DIST += \ $(man_ADOC_FILES) # # usbguard icon # EXTRA_DIST += \ $(top_builddir)/icons/usbguard-icon.svg $(top_builddir)/src/usbguard-icon.hpp: $(top_builddir)/icons/usbguard-icon.svg echo -e "#ifndef ICON_HPP\n#define ICON_HPP\nnamespace notify {\nconst char *icon =" > $@ $(SED) 's/"/\\"/g' $^ | $(SED) 's/^/"/' | $(SED) 's/$$/\\n"/' >> $@ echo -e ";\n}\n#endif" >> $@ CLEANFILES += \ $(top_builddir)/src/usbguard-icon.hpp # # unit file # install-data-hook: install-systemd-service uninstall-hook: uninstall-systemd-service CLEANFILES += $(top_builddir)/usbguard-notifier.service # # Notifier service # EXTRA_DIST += \ $(top_srcdir)/usbguard-notifier.service.in usbguard-notifier.service: $(top_srcdir)/usbguard-notifier.service.in $(SED) -e "s|%bindir%|${bindir}|" $^ > $@ || rm -f $@ install-systemd-service: $(top_builddir)/usbguard-notifier.service $(MKDIR_P) $(DESTDIR)$(SYSTEMD_UNIT_DIR) $(INSTALL) -m 644 $(top_builddir)/usbguard-notifier.service \ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/usbguard-notifier.service uninstall-systemd-service: rm -f $(DESTDIR)$(SYSTEMD_UNIT_DIR)/usbguard-notifier.service CLEANFILES += $(top_builddir)/usbguard-notifier.service # # Common defines # $(top_builddir)/src/BuildConfig.h: $(top_builddir)/src/BuildConfig.h.in $(SED) -e "s|%NOTIFICATION_PATH%|@NOTIFICATION_PATH@|g" $^ > $@ || rm -f $@ $(MKDIR_P) @NOTIFICATION_PATH@ CLEANFILES += $(top_builddir)/src/BuildConfig.h usbguard-notifier-0.1.0/README.md000066400000000000000000000037441435004305000164220ustar00rootroot00000000000000# USBGuard Notifier [![License](https://img.shields.io/github/license/Cropi/usbguard-notifier.svg)](LICENSE) ### About USBGuard Notifier is a software framework mainly for detecting usbguard policy modifications as well as device presence changes. In a nutshell, the purpose of this project is to create user-friendly notifications in form of quick pop-up messages. ### Dependencies In order to compile the sources from a tarball/zip you will need the following development files: * [usbguard](https://github.com/USBGuard/usbguard/) * [libnotify](https://github.com/GNOME/libnotify) * [librsvg](https://github.com/GNOME/librsvg) * [asciidoc](https://github.com/asciidoc/asciidoc) ### Instalation It is pretty easy to install the USBGuard Notifier. There are two possibilities how to install it: * per user (locally) ``` $ ./autogen.sh ``` Now you can choose if you would like to store the notifications temporarily(until reboot): ``` $ ./configure --prefix /home/$(id -un) ``` or permanently: ``` $ ./configure --prefix /home/$(id -un) --with-permanent-notifications=path/to/dir ``` ``` $ make $ make install SYSTEMD_UNIT_DIR=/home/$(id -un)/.config/systemd/user/ $ systemctl enable --now --user usbguard-notifier.service ``` ### Note You might get an **IPC connection** error while trying to execute the binary program. It means the usbguard.service stopped working or you have not started it yet. If you want to compile the sources in a cloned repository, you’ll have to run the ./autogen.sh script. It will fetch the sources (via git submodule) of [CATCH](https://github.com/catchorg/Catch2/). The script will then initialize the autotools based build system. USBGuard Notifier has to use the same version of usbguard-devel package that USBGuard uses in your system. ### Contribution You may want to extend the features of USBGuard Notifier. Contributions are welcome and will be fully credited. We accept contributions via Pull Requests on Github. ### License GNU General Public License v2.0 usbguard-notifier-0.1.0/RELEASE_PROCESS.md000066400000000000000000000017541435004305000177420ustar00rootroot00000000000000# USBGuard Notifier Release Process 1. Clean up any artifact from your local repository. ``` $ git clean -x -f -d ``` 2. Update the AC_INIT field in `configure.ac` and `CHANGELOG.md`. Commit your changes. 3. Build the final release tarball. ``` $ ./autogen.sh $ ./configure $ make dist ``` 4. Tag the release with a signed tag. ``` $ git tag -s -m "usbguard-notifier-0.x.y" usbguard-notifier-0.x.y $ git push origin usbguard-notifier-0.x.x ``` 5. Hash and sign the release. ``` $ sha256sum usbguard-notifier-0.x.y.tar.gz > usbguard-notifier-0.x.y.tar.gz.sum $ gpg --armor --detach-sign usbguard-notifier-0.x.y.tar.gz $ gpg --clearsign usbguard-notifier-0.x.y.tar.gz.sum ``` 6. Create a new GitHub release using the associated tag; add the relevant section from CHANGELOG.md. Upload: * usbguard-notifier-0.x.y.tar.gz * usbguard-notifier-0.x.y.tar.gz.asc * usbguard-notifier-0.x.y.tar.gz.sum * usbguard-notifier-0.x.y.tar.gz.sum.asc 7. Edit(if needed) the new Github release. usbguard-notifier-0.1.0/autogen.sh000077500000000000000000000000751435004305000171360ustar00rootroot00000000000000mkdir -p m4 git submodule update --init autoreconf --install usbguard-notifier-0.1.0/configure.ac000066400000000000000000000142741435004305000174310ustar00rootroot00000000000000AC_PREREQ([2.69]) AC_INIT([usbguard-notifier], [0.1.0], [alakatos@redhat.com]) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_AUX_DIR([config]) AC_CONFIG_MACRO_DIR([m4]) m4_pattern_allow([AC_MSG_FAILURE]) # if it's possible enable silent compilation m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) EXTERNAL_CXXFLAGS="$CXXFLAGS" AM_INIT_AUTOMAKE([foreign subdir-objects tar-pax]) AC_PROG_MAKE_SET AC_PROG_CXX AC_PROG_CC_C99 AC_PROG_INSTALL AC_PROG_MAKE_SET LT_PREREQ([2.4.6]) LT_INIT # Check for headers, typedefs, data structures AC_CHECK_HEADER_STDBOOL AC_C_INLINE AC_TYPE_INT16_T AC_TYPE_INT32_T AC_TYPE_INT64_T AC_TYPE_UINT16_T AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_TYPE_UINT8_T AC_CHECK_HEADERS([getopt.h unistd.h], [], [AC_MSG_ERROR([Required header file(s) not found])], []) # As default each argument is stored temporiraly, however with this options it can be modified notification_path="/tmp/usbguard-notifier" AC_ARG_WITH( [permanent-notifications], AS_HELP_STRING([--with-permanent-notifications], [Select notifications path]), [notification_path=$withval], [notificaiton_path="/tmp/usbguard-notifier"] ) # usbguard-devel # Add the path to where your usbguard-devel includes are # You might need this option when you want to package usbguard-notifier # together with usbguard at the same time AC_ARG_WITH( [usbguard-devel], AS_HELP_STRING([--with-usbguard-devel], [Select to compile notifier from source usbguard devel files(only top level directory)]), [usbguard_CFLAGS="-I$withval/src/Library/public/" usbguard_LIBS="" usbguard_LA="$withval/libusbguard.la" libusbguard_summary="$usbguard_CFLAGS $usbguard_LIBS" AC_SUBST([usbguard_CFLAGS]) AC_SUBST([usbguard_LIBS]) AC_SUBST([usbguard_LA]) custom_usbguard_devel_enabled=yes ], [ PKG_CHECK_MODULES( [usbguard], [libusbguard >= 0.7.2], [libusbguard_summary="$usbguard_CFLAGS $usbguard_LIBS"], [AC_MSG_FAILURE([libusbguard development files not found])] ) ] ) # Build notifier-cli, default is yes AC_ARG_ENABLE([notifier-cli], [AC_HELP_STRING([--enable-notifier-cli], [enable notifier cli(default=yes)])], [case "${enableval}" in yes) notifier_cli_enabled=yes;; no) notifier_cli_enabled=no;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-notifier-cli]) ;; esac], [notifier_cli_enabled=yes] ) AC_ARG_ENABLE([systemd-systemunitdir], [AC_HELP_STRING([--enable-systemd-systemunitdir], [enable systemd system unit dir(default=no)])], [case "${enableval}" in yes) systemd_systemunitdir=yes;; no) systemd_systemunitdir=no;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-systemd-systemunitdir]) ;; esac], [systemd_systemunitdir=no] ) # librsvg2 PKG_CHECK_MODULES( [rsvg], [librsvg-2.0 >= 2.0.0], [librsvg_summary="$rsvg_CFLAGS $rsvg_LIBS"], [AC_MSG_FAILURE([librsvg2 development files not found])] ) # libnotify PKG_CHECK_MODULES( [notify], [libnotify >= 0.7.0], [libnotify_summary="$notify_CFLAGS $notify_LIBS"], [AC_MSG_FAILURE([libnotify development files not found])] ) # asciidoc AC_CHECK_PROGS(A2X, [a2x]) if test -z "$A2X"; then AC_MSG_FAILURE([Cannot detect documentation generator (asciidoc / a2x)]) fi # systemd if test "x$systemd_systemunitdir" = xyes; then systemd_unit_dir="`$PKG_CONFIG systemd --variable=systemdsystemunitdir`" else systemd_unit_dir="`$PKG_CONFIG systemd --variable=systemduserunitdir`" fi if test "x$systemd_unit_dir" = x; then AC_MSG_FAILURE([Cannot detect the systemd system unit dir]) fi AC_SUBST(SYSTEMD_UNIT_DIR, $systemd_unit_dir) AC_DEFINE([SYSTEMD_SUPPORT_ENABLED], [1], [Enable systemd support int the project]) AM_CONDITIONAL([SYSTEMD_SUPPORT_ENABLED], [test "x$systemd" = xyes ]) # Catch C++ library AC_ARG_WITH([bundled-catch], AS_HELP_STRING([--with-bundled-catch], [Build using the bundled Catch library]), [with_bundled_catch=$withval], [with_bundled_catch=no]) if test "x$with_bundled_catch" = xyes; then catch_CFLAGS="-I\$(top_srcdir)/src/ThirdParty/Catch2/single_include/catch2" catch_LIBS="" AC_MSG_NOTICE([Using bundled Catch library]) catch_summary="bundled; $catch_CFLAGS $catch_LIBS" else SAVE_CPPFLAGS=$CPPFLAGS CPPFLAGS="-std=c++11 $CPPFLAGS -I/usr/include/catch" AC_LANG_PUSH([C++]) AC_CHECK_HEADER([catch.hpp], [], [AC_MSG_FAILURE(catch.hpp not found or not usable. Re-run with --with-bundled-catch to use the bundled library.)]) AC_LANG_POP catch_CFLAGS="-I/usr/include/catch" catch_LIBS="" CPPFLAGS=$SAVE_CPPFLAGS catch_summary="system-wide; $catch_CFLAGS $catch_LIBS" fi AC_SUBST([catch_CFLAGS]) AC_SUBST([catch_LIBS]) CXXFLAGS_DEBUG="-g -O2" AC_ARG_ENABLE( [debug-build], [AC_HELP_STRING([--enable-debug-build], [enable debugging flags (default=no)])], [case "${enableval}" in yes) debug=yes ;; no) debug=no ;; *) AC_MSG_ERROR([bad value ${enableval} for --enable-debug-build]) ;; esac], [debug=no] ) CXXFLAGS=" $EXTERNAL_CXXFLAGS" CXXFLAGS+=" -std=c++11" CXXFLAGS+=" -pedantic" CXXFLAGS+=" -Wno-unknown-pragmas" CXXFLAGS+=" -Wall" CXXFLAGS+=" -Wextra" if test "x$debug" = xyes; then CXXFLAGS="$CXXFLAGS $CXXFLAGS_DEBUG" fi AC_SUBST(CPPFLAGS, $CXXFLAGS) AC_SUBST(config_PATH, $prefix/.config) AC_SUBST(NOTIFICATION_PATH, $notification_path) AM_CONDITIONAL([NOTIFIER_CLI_ENABLED], [test "x$notifier_cli_enabled" = xyes ]) AM_CONDITIONAL([CUSTOM_USBGUARD_DEVEL_ENABLED], [test "x$custom_usbguard_devel_enabled" = "xyes"]) AC_CONFIG_FILES([ Makefile src/Tests/Makefile ]) AC_OUTPUT echo "" echo "============== MACROS =================" echo " systemd: $systemd_unit_dir" echo "" echo "========== LINKER OPTIONS =============" echo " Catch: $catch_summary" echo " libnotify: $libnotify_summary" echo " libusbguard: $libusbguard_summary" echo " librsvg: $librsvg_summary" echo " CXXFLAGS: $CXXFLAGS" echo "" echo "============= ARGUMENTS ===============" echo " prefix: $prefix" echo " config_file: $prefix/.conf" echo "notification_path: $notification_path" echo " notifier_cli: $notifier_cli_enabled" echo "" usbguard-notifier-0.1.0/icons/000077500000000000000000000000001435004305000162465ustar00rootroot00000000000000usbguard-notifier-0.1.0/icons/usbguard-icon.svg000066400000000000000000000150701435004305000215340ustar00rootroot00000000000000 USBGuard logo image/svg+xml USBGuard logo Daniel Kopeček USB Guard Logo Official USBGuard project logo. https://github.com/dkopecek/usbguard/ 2016 usbguard-notifier-0.1.0/man/000077500000000000000000000000001435004305000157065ustar00rootroot00000000000000usbguard-notifier-0.1.0/man/footer.adoc000066400000000000000000000011041435004305000200300ustar00rootroot00000000000000== BUGS If you find a bug in this software or if you'd like to request a feature to be implemented, please file a ticket at . == AUTHOR USBGuard Notifier was written by Zoltán Fridrich and Attila Lakatos. == RESOURCES Main web site: == COPYING Copyright © 2015-{docyear} Red Hat, Inc. + License GPLv2+: GNU GPL version 2 or later http://gnu.org/licenses/gpl.html. + This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. usbguard-notifier-0.1.0/man/usbguard-notifier-cli.1.adoc000066400000000000000000000033561435004305000231020ustar00rootroot00000000000000usbguard-notifier-cli(1) ======================== :doctype: manpage == NAME usbguard-notifier-cli - USBGuard Notifier command-line interface == SYNOPSIS usbguard-notifier [OPTIONS] == DESCRIPTION USBGuard Notifier CLI is command line application used to display, manage, edit and remove notifications generated by usbguard-notifier. == OPTIONS *-h, --help*:: Show help. == COMMANDS Each command is typed on a line by itself, and may take arguments following the command word. The following commands are provided: *show *:: Shows every single notification based on the given property. If no arguments are given, 'all' option will be applied. *display *:: Provides a detailed description about a single notification identified by 'id'. *next *:: Moves cursor to the x-th next notification specified by 'id' and applies the *display* method. If no arguments are given, it will move on to the next notification. *previous *:: Moveis cursor to the x-th previous notification specified by 'id' and applies the *display* method. If no arguments are given, it will move on to the previous notification. *remove *:: Removes one or more notifications specified by 'id'. If no arguments are given, removes the actual notification. *help*:: Detailed description about each command. *commands*:: List of all available commands. *quit*:: Terminates the session, saving all undeleted notifications. == NOTE Please note that each command has a shortcut. To view detailed description about commands and their appropriate shortcuts, as well as parameters type 'help'. == SEE ALSO link:usbguard-notifier.1.adoc#name[usbguard-notifier(1)] include::footer.adoc[] usbguard-notifier-0.1.0/man/usbguard-notifier.1.adoc000066400000000000000000000036041435004305000223310ustar00rootroot00000000000000usbguard-notifier(1) ==================== :doctype: manpage == NAME usbguard-notifier - provides user-friendly notifications for USBGuard == SYNOPSIS usbguard-notifier [OPTIONS] == DESCRIPTION USBGuard Notifier is a software framework mainly for detecting usbguard policy modifications as well as device presence changes. The purpose of this project is to create user-friendly notifications in form of quick pop-up messages. == OPTIONS *-w, --wait*:: Wait until an active IPC connection is estabilished. *-d, --debug*:: Enable debug mode. *-h, --help*:: Show help. == HOW TO START In order to make usbguard-notifier work properly, you will need to perform certain actions: 1. Each user who wants to run usbguard-notifier service needs to have sufficient IPC privileges to connect to the usbguard IPC interface. To allow a specific user to listen to the device signals you can use the following command: + + *$ sudo usbguard add-user* 'USER' *-d listen* + + Or you can allow a group of users: + + *$ sudo usbguard add-user -g* 'GROUP' *-d listen* 2. Now, you need a running usbguard-daemon instance to connect to. Start the usbguard service or restart it if it is already running. 3. After configuring IPC privileges and starting up the usbguard-daemon, the user can now start the usbguard-notifier service: + + *$ systemctl start --user usbguard-notifier.service* + + Optionally, the user can enable the usbguard-notifier service to start automatically after the login: + + *$ systemctl enable --user usbguard-notifier.service* The usbguard-notifier should now be running. Anytime a USB device gets inserted/ejected or allowed/blocked a message will pop up in the user's graphical interface. == SEE ALSO link:usbguard-notifier-cli.1.adoc#name[usbguard-notifier-cli(1)], link:usbguard.1.adoc#name[usbguard(1)] include::footer.adoc[] usbguard-notifier-0.1.0/scripts/000077500000000000000000000000001435004305000166225ustar00rootroot00000000000000usbguard-notifier-0.1.0/scripts/restyle.sh000077500000000000000000000007611435004305000206540ustar00rootroot00000000000000#!/bin/bash DIRNAME="$(dirname "$0")/../" FILES=`find ${DIRNAME} -name "*.cpp" -or -name "*.hpp"` OPTIONS=" --style=kr \ --indent=spaces=4 \ --indent-after-parens \ --indent-labels \ --indent-col1-comments \ --pad-oper \ --pad-comma \ --pad-header \ --convert-tabs \ --attach-closing-while \ --attach-return-type \ --attach-return-type-decl \ --add-braces \ --align-pointer=type \ --align-reference=type \ --keep-one-line-blocks \ --max-code-length=128 \ --suffix=none " astyle $OPTIONS $FILES usbguard-notifier-0.1.0/src/000077500000000000000000000000001435004305000157225ustar00rootroot00000000000000usbguard-notifier-0.1.0/src/BuildConfig.h.in000066400000000000000000000001131435004305000206600ustar00rootroot00000000000000/* * Notification file */ #define NOTIFICATION_DIR "%NOTIFICATION_PATH%" usbguard-notifier-0.1.0/src/Log.cpp000066400000000000000000000035121435004305000171500ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos */ #include "Log.hpp" #include namespace usbguardNotifier { Logger g_nLog; Logger::Logger(bool debug) : _debug(debug) {} LoggerStream Logger::createLogMessage( const std::string& file, const std::string& function, int line) { return LoggerStream(*this, { file, function, line }); } void Logger::setDebugMode(bool debug) noexcept { _debug = debug; } bool Logger::isEnabled() const noexcept { return _debug; } LoggerStream::LoggerStream(Logger& logger, Source source) : _logger(logger), _source(source) {} LoggerStream::LoggerStream(const LoggerStream& rhs) : std::basic_ios(), std::ostringstream(rhs.str()), _logger(rhs._logger), _source(rhs._source) {} LoggerStream::~LoggerStream() { writeLogMessage(); } void LoggerStream::writeLogMessage() const { std::cout << "LOG: " << _source.file << "::"; std::cout << _source.line; std::cout << " [" << _source.function << "] "; std::cout << str(); std::cout << std::endl; } } // namespace usbuard-notifier usbguard-notifier-0.1.0/src/Log.hpp000066400000000000000000000034171435004305000171610ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos */ #ifndef LOG_HPP #define LOG_HPP #include #include #define NOTIFIER_LOGGER usbguardNotifier::g_nLog #define NOTIFIER_LOG() \ if (NOTIFIER_LOGGER.isEnabled()) \ usbguardNotifier::g_nLog.createLogMessage(__BASE_FILE__, __func__, __LINE__) namespace usbguardNotifier { class LoggerStream; class Logger { public: Logger(bool debug = false); LoggerStream createLogMessage( const std::string& file, const std::string& function, int line); void setDebugMode(bool debug) noexcept; bool isEnabled() const noexcept; private: bool _debug; }; class LoggerStream : public std::ostringstream { public: struct Source { const std::string& file; const std::string& function; const int line; }; LoggerStream(Logger& logger, Source source); LoggerStream(const LoggerStream& rhs); ~LoggerStream(); private: void writeLogMessage() const; Logger _logger; Source _source; }; extern Logger g_nLog; } // namespace usbguardNotifier #endif usbguard-notifier-0.1.0/src/Main.cpp000066400000000000000000000065221435004305000173170ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos */ #include "Log.hpp" #include "Notifier.hpp" #include #include #include #include #include #include static const char* short_options = "wn:dh"; static const struct ::option long_options[] = { { "wait", no_argument, nullptr, 'w' }, { "num-attempts", required_argument, nullptr, 'n' }, { "debug", no_argument, nullptr, 'd' }, { "help", no_argument, nullptr, 'h' } }; void showHelp(const std::string& app_name, std::ostream& out) { out << "Usage: " << app_name << " [OPTIONS]" << std::endl; out << std::endl; out << "Options:" << std::endl; out << " -w, --wait Wait until an active IPC connection is estabilished." << std::endl; out << " -n, --num-attempts Number of IPC connection attempts." << std::endl; out << " -d, --debug Enable debug mode." << std::endl; out << " -h, --help Show this usage message." << std::endl; } int main(int argc, char** argv) { const std::string app_name(::basename(*argv)); bool wait_connection = false, debug = false; int opt, num_attempts = 3; while ((opt = getopt_long(argc, argv, short_options, long_options, nullptr)) != -1) { switch (opt) { case 'w': wait_connection = true; break; case 'n': num_attempts = std::atoi(optarg); break; case 'd': debug = true; break; case 'h': showHelp(app_name, std::cout); return EXIT_SUCCESS; case '?': showHelp(app_name, std::cerr); return EXIT_FAILURE; default: return EXIT_FAILURE; } } NOTIFIER_LOGGER.setDebugMode(debug); bool print_err = true; for (int i = 0; wait_connection || i < num_attempts; ++i) { try { usbguardNotifier::Notifier notifier(app_name); notifier.connect(); std::cout << "Connection has been established" << std::endl; print_err = true; i = 0; notifier.wait(); } catch (const std::runtime_error& e) { std::cerr << "Error:" << e.what() << std::endl; return EXIT_FAILURE; } catch (const usbguard::Exception& e) { if (print_err) { print_err = false; std::cerr << "IPC connection failure!" << e.message() << std::endl; std::cerr << "Check if usbguard-daemon is running in the background" << std::endl; } } sleep(1); } return EXIT_SUCCESS; } usbguard-notifier-0.1.0/src/MainCli.cpp000066400000000000000000000061021435004305000177410ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos * Zoltán Fridrich */ #include "BuildConfig.h" #include "NotifierCLI.hpp" #include #include #include #include #include #include static const char* shortOptions = "h"; static const struct ::option longOptions[] = { { "help", no_argument, nullptr, 'h' } }; void showHelp(const std::string& app_name, std::ostream& out) { out << "Usage: " << app_name << " [OPTIONS]" << std::endl; out << std::endl; out << "Options:" << std::endl; out << " -h, --help Show this usage message." << std::endl; } int main(int argc, char** argv) { using namespace usbguardNotifier; const std::string app_name(::basename(*argv)); int opt; while ((opt = getopt_long(argc, argv, shortOptions, longOptions, nullptr)) != -1) { switch (opt) { case 'h': showHelp(app_name, std::cout); return EXIT_SUCCESS; case '?': showHelp(app_name, std::cerr); return EXIT_FAILURE; default: return EXIT_FAILURE; } } // Load notifications from file std::string notification_path(std::string(NOTIFICATION_DIR) + "/" + std::string(getlogin())); Serializer serializer(notification_path); std::map map; try { map = serializer.deserializeAll(); } catch (std::runtime_error& e) { std::cerr << "Error: file " << notification_path << " doesn't exist." << std::endl; return EXIT_FAILURE; } if (map.empty()) { std::cout << "No notifications to show." << std::endl; return EXIT_SUCCESS; } CLI notifier(map); CLI::Command cmd_code = CLI::Command::UNKNOWN; std::string line, cmd_name, cmd_options; while (cmd_code != CLI::Command::QUIT) { std::cout << "& "; std::cin >> cmd_name; std::getline(std::cin, cmd_options); cmd_options.erase(0, cmd_options.find_first_not_of(' ')); try { cmd_code = notifier.execute(cmd_name, cmd_options); } catch (std::runtime_error& e) { std::cerr << e.what() << std::endl; } if (cmd_code == CLI::Command::UNKNOWN) { std::cerr << "Unknown command." << std::endl; } } return EXIT_SUCCESS; } usbguard-notifier-0.1.0/src/Notifier.cpp000066400000000000000000000160051435004305000202070ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos */ #include "BuildConfig.h" #include "Log.hpp" #include "Notifier.hpp" #include #include #include #include #include #include #include #include #include namespace usbguardNotifier { Notifier::Notifier(const std::string& app_name) : _lib(app_name) { std::string login = getlogin() ? getlogin() : "unknown"; std::string path(std::string(NOTIFICATION_DIR) + "/" + login); _ser.setFileName(path); // g_mail_loop is required by action's callback _GMLoop = g_main_loop_new(nullptr, FALSE); _GMLoopThread = new std::thread( [this] { g_main_loop_run(_GMLoop); } ); _actionsCallbackUserData.object_ptr = this; _actionsCallbackUserData.info = nullptr; } Notifier::~Notifier() { for (auto t : _countdownThreads) { t->join(); delete t; } g_main_loop_quit(_GMLoop); _GMLoopThread->join(); delete _GMLoopThread; } void Notifier::DevicePolicyChanged( uint32_t id, usbguard::Rule::Target target_old, usbguard::Rule::Target target_new, const std::string& device_rule, uint32_t rule_id) { using namespace usbguard; NOTIFIER_LOG() << "Device policy changed signal"; const std::string target_old_str = Rule::targetToString(target_old); const std::string target_new_str = Rule::targetToString(target_new); DevicePresenceInfo info = getDevicePresenceObject(id); if (info.isInitialized) { if (info.target == target_old || device_rule.substr(target_new_str.size()) == info.device_rule.substr(target_old_str.size())) { info.target = target_new; sendDevicePresenceNotification(info); return; } else { NOTIFIER_LOG() << "DevicePolicyChanged and DevicePresenceChanged " << "with same id do not share the same rule."; } } Rule rule = Rule::fromString(device_rule); std::ostringstream body; body << rule.getName() << ": " << target_new_str << "ed"; notify::Notification n("Update - USBGuard", body.str()); if (!n.show()) { throw std::runtime_error("Failed to show notification"); } NOTIFIER_LOG() << "Store notification"; Notification obj = { __func__, id, rule.getName(), target_old_str, target_new_str, rule_id, device_rule }; _ser.serialize(obj); } void Notifier::DevicePresenceChanged( uint32_t id, usbguard::DeviceManager::EventType event, usbguard::Rule::Target target, const std::string& device_rule) { using namespace usbguard; NOTIFIER_LOG() << "Device presence changed signal"; _deviceNotifications.emplace(std::make_pair(id, DevicePresenceInfo(id, event, target, device_rule))); std::thread* t = new std::thread( [this, id] { sendDevicePresenceCountdownCallback(id); } ); _countdownThreads.push_back(t); } Notifier::DevicePresenceInfo Notifier::getDevicePresenceObject(uint32_t id) { DevicePresenceInfo info; _mtx.lock(); auto it = _deviceNotifications.find(id); if (it != _deviceNotifications.end()) { info = it->second; _deviceNotifications.erase(it); } _mtx.unlock(); return info; } void Notifier::sendDevicePresenceCountdownCallback(uint32_t id) { std::this_thread::sleep_for(std::chrono::milliseconds(_kMillisecondsDevicePolicyWait)); DevicePresenceInfo info = getDevicePresenceObject(id); if (info.isInitialized) { sendDevicePresenceNotification(info); } } void Notifier::sendDevicePresenceNotification(DevicePresenceInfo& info) { using namespace usbguard; const std::string event_str = DeviceManager::eventTypeToString(info.event); const std::string target_str = Rule::targetToString(info.target); Rule rule = Rule::fromString(info.device_rule); std::ostringstream body; if (info.event == DeviceManager::EventType::Remove) { body << rule.getName(); } else { body << rule.getName() << ": " << target_str << "ed"; } notify::Notification n(event_str + " - USBGuard", body.str()); n.setTimeout(5000); n.setCategory("device"); if (info.event == DeviceManager::EventType::Insert) { _actionsCallbackUserData.info = &info; if (info.target != Rule::Target::Allow) { n.addAction(Rule::targetToString(Rule::Target::Allow), "Allow", &Notifier::actionsCallbackWrapper, &_actionsCallbackUserData); } n.addAction(Rule::targetToString(Rule::Target::Reject), "Reject", &Notifier::actionsCallbackWrapper, &_actionsCallbackUserData); } if (!n.show()) { throw std::runtime_error("Failed to show notification"); } // TODO serialize } void Notifier::actionsCallback(const std::string& action_id, DevicePresenceInfo* info) { using namespace usbguard; try { if (Rule::targetFromString(action_id) == Rule::Target::Allow) { IPCClient::applyDevicePolicy(info->id, usbguard::Rule::Target::Allow, false); } else if (Rule::targetFromString(action_id) == Rule::Target::Reject) { IPCClient::applyDevicePolicy(info->id, usbguard::Rule::Target::Reject, false); } NOTIFIER_LOG() << "Device Policy '" << action_id << "' applied to device with ID: " << info->id; } catch (const usbguard::IPCException& ex) { std::cerr << "IPC call failed while trying to apply device policy" << " '" << action_id << "' over device with ID " << info->id << " with message:" << std::endl; std::cerr << ex.message() << std::endl; } catch (const std::exception& ex) { std::cerr << "IPC call failed while trying to apply device policy" << " '" << action_id << "' over device with ID " << info->id << " with message:" << std::endl; std::cerr << ex.what() << std::endl; } } void Notifier::actionsCallbackWrapper(NotifyNotification* n __attribute__((unused)), char* action, gpointer user_data) { using namespace usbguardNotifier; // Cast struct here for better readability auto ud = static_cast(user_data); // Call member callback ud->object_ptr->actionsCallback(action, ud->info); } } // namespace usbguardNotifier usbguard-notifier-0.1.0/src/Notifier.hpp000066400000000000000000000100701435004305000202100ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos */ #ifndef NOTIFIER_HPP #define NOTIFIER_HPP #include "NotifyWrapper.hpp" #include "Serializer.hpp" #include #include #include #include namespace usbguardNotifier { class Notifier : public usbguard::IPCClient { public: explicit Notifier(const std::string& app_name); ~Notifier(); void DevicePolicyChanged( uint32_t id, usbguard::Rule::Target target_old, usbguard::Rule::Target target_new, const std::string& device_rule, uint32_t rule_id) override; void DevicePresenceChanged( uint32_t id, usbguard::DeviceManager::EventType event, usbguard::Rule::Target target, const std::string& device_rule) override; /* void PropertyParameterChanged( const std::string& name, const std::string& value_old, const std::string& value_new); */ /** * @brief Notification action's C-style callback * This callback later calls private method 'actionsCallback' which is the "desired" * callback as it can access class members. * * @see \link notify::Notification::addAction addAction\endlink * * @param n Not in use. Imposed by libnotify API. * @param action Action ID. * @param user_data Pointer to _actionsCallbackUserData in an object instance. */ static void actionsCallbackWrapper( NotifyNotification* n, char* action, gpointer user_data); private: struct DevicePresenceInfo { bool isInitialized = false; uint32_t id; usbguard::DeviceManager::EventType event; usbguard::Rule::Target target; std::string device_rule; DevicePresenceInfo(const uint32_t id, const usbguard::DeviceManager::EventType& e, const usbguard::Rule::Target& t, const std::string& r): isInitialized(true), id(id), event(e), target(t), device_rule(r) {} DevicePresenceInfo() : id(0), event(), target(), device_rule() {} }; /** * @brief Structure passed as argument in notification action's callback. * * @see \link Notification::addAction addAction\endlink * @see \link Notifier::actionsCallback actionsCallback\endlink */ struct ActionsCallbackUserData { Notifier* object_ptr; /**< Reference to class instance. */ DevicePresenceInfo* info; /**< Device information needed by \link actionsCallback actionsCallback\endlink method. */ ActionsCallbackUserData(Notifier* ctx, DevicePresenceInfo* info) : object_ptr(ctx), info(info) {}; ActionsCallbackUserData() : object_ptr(nullptr), info(nullptr) {}; }; DevicePresenceInfo getDevicePresenceObject(uint32_t id); void sendDevicePresenceCountdownCallback(uint32_t id); void sendDevicePresenceNotification(DevicePresenceInfo& info); void actionsCallback(const std::string& action_id, DevicePresenceInfo* info); notify::Notify _lib; Serializer _ser; std::map _deviceNotifications; std::mutex _mtx; std::vector _countdownThreads; const int _kMillisecondsDevicePolicyWait = 500; GMainLoop* _GMLoop; std::thread* _GMLoopThread; ActionsCallbackUserData _actionsCallbackUserData; }; } // namespace usbguardNotifier #endif // NOTIFIER_HPP usbguard-notifier-0.1.0/src/NotifierCLI.cpp000066400000000000000000000116011435004305000205340ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos * Zoltán Fridrich */ #include "NotifierCLI.hpp" #include #include namespace usbguardNotifier { struct cmd_cmp { bool operator()(const std::string& lhs, const std::string& rhs) const { return (lhs.length() == 1 || rhs.length() == 1) ? lhs.front() < rhs.front() : lhs < rhs; } }; struct cmd_data { CLI::Command code; void(CLI::*command)(const std::string&); std::string description; }; static const std::map commands = { { "show", { CLI::Command::SHOW, &CLI::show, "Show all notifications." } }, { "display", { CLI::Command::DISPLAY, &CLI::display, "Display detailed description of current notification." } }, { "jump", { CLI::Command::JUMP, &CLI::jump, "Jump to the specified index." } }, { "next", { CLI::Command::NEXT, &CLI::next, "Move cursor to next notification." } }, { "previous", { CLI::Command::PREVIOUS, &CLI::previous, "Move cursor to previous notification." } }, { "help", { CLI::Command::HELP, &CLI::help, "Show this help." } }, { "list", { CLI::Command::LIST, &CLI::list, "List all available commands." } }, { "quit", { CLI::Command::QUIT, &CLI::quit, "Quit CLI." } } }; CLI::CLI(const CLI::map& db) : _db(db), _iter(_db.cbegin()) {} CLI::Command CLI::execute( const std::string& cmd_name, const std::string& cmd_options) { const auto iterator = commands.find(cmd_name); if (iterator == commands.cend()) { return CLI::Command::UNKNOWN; } auto command = iterator->second.command; (*this.*command)(cmd_options); return iterator->second.code; } void CLI::show(const std::string& options) { for (const auto& x : _db) { std::string line = std::string(x.first == _iter->first ? ">" : " ") + "#" + std::to_string(x.first) + ": " + x.second.event_type + " <" + x.second.device_name + "> " + x.second.target_new; if (line.find(options) != std::string::npos) { std::cout << line << std::endl; } } } void CLI::display(const std::string& /*options*/) { std::cout << "Notification #" << _iter->first << ":\n"; std::cout << " Name: " << _iter->second.device_name << '\n'; std::cout << " Type: " << _iter->second.event_type << '\n'; std::cout << " Old value: " << _iter->second.target_old << '\n'; std::cout << " New value: " << _iter->second.target_new << '\n'; std::cout << " Rule: " << _iter->second.rule << std::endl; } void CLI::jump(const std::string& options) { try { auto i = _db.find(static_cast(std::stoul(options))); if (i == _db.cend()) { std::cerr << "There is no element with such index." << std::endl; return; } _iter = i; } catch (std::logic_error& e) { std::cerr << "Invalid index passed to jump." << std::endl; return; } } void CLI::next(const std::string& /*options*/) { if (_db.empty() || _iter == std::prev(_db.cend())) { std::cout << "At EOF." << std::endl; return; } _iter = std::next(_iter); } void CLI::previous(const std::string& /*options*/) { if (_iter == _db.cbegin()) { return; } _iter = std::prev(_iter); } void CLI::help(const std::string& /*options*/) { for (const auto& i : commands) { std::cout << i.first.front() << ", " << i.first << " - " << i.second.description << std::endl; } } void CLI::list(const std::string& /*options*/) { for (const auto& i : commands) { std::cout << i.first << std::endl; } } void CLI::quit(const std::string& /*options*/) { } const CLI::map& CLI::getDb() const noexcept { return _db; } const CLI::map::const_iterator& CLI::getIterator() const noexcept { return _iter; } } usbguard-notifier-0.1.0/src/NotifierCLI.hpp000066400000000000000000000042611435004305000205450ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Attila Lakatos * Zoltán Fridrich */ #ifndef NOTIFIER_CLI_HPP #define NOTIFIER_CLI_HPP #include "Serializer.hpp" #include #include namespace usbguardNotifier { class CLI { public: using map = typename std::map; enum class Command { UNKNOWN, SHOW, DISPLAY, JUMP, NEXT, PREVIOUS, HELP, LIST, QUIT }; /** * @brief Constructs usbguard-notifier CLI. * * @param db Database of notifications. */ explicit CLI(const map& db); /** * @brief Parse and execute given command. * * @param cmd_name Name of the command. * @param cmd_options Options passed to the command. * * @return Command code. */ Command execute( const std::string& cmd_name, const std::string& cmd_options); void show(const std::string& options); void display(const std::string& options); void jump(const std::string& options); void next(const std::string& options); void previous(const std::string& options); void help(const std::string& options); void list(const std::string& options); void quit(const std::string& options); const map& getDb() const noexcept; const map::const_iterator& getIterator() const noexcept; private: const map& _db; map::const_iterator _iter; }; } // namespace usbguardNotifier #endif // NOTIFIER_CLI_HPP usbguard-notifier-0.1.0/src/NotifyWrapper.cpp000066400000000000000000000054451435004305000212470ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Zoltán Fridrich */ #include "NotifyWrapper.hpp" #include "usbguard-icon.hpp" #include #include #include namespace notify { Notify::Notify(const std::string& app_name) { if (!notify_init(app_name.c_str())) { throw std::runtime_error("Failed to initialize libnotify"); } } Notify::~Notify() { notify_uninit(); } std::string Notify::getAppName() const noexcept { return { notify_get_app_name() }; } void Notify::setAppName(const std::string& app_name) { notify_set_app_name(app_name.c_str()); } Notification::Notification(const std::string& summary, const std::string& body) : _n(notify_notification_new(summary.c_str(), body.c_str(), nullptr)) { RsvgHandle* handle = rsvg_handle_new_from_data((const guint8*)icon, std::strlen(icon), nullptr); if (!handle) { throw std::runtime_error("Failed to obtain rsvg handle"); } GdkPixbuf* pixbuf = rsvg_handle_get_pixbuf(handle); notify_notification_set_image_from_pixbuf(_n, pixbuf); g_object_unref(handle); } bool Notification::update(const std::string& summary, const std::string& body) { return notify_notification_update(_n, summary.c_str(), body.c_str(), nullptr); } bool Notification::show() const { return notify_notification_show(_n, nullptr); } void Notification::setTimeout(int timeout) noexcept { notify_notification_set_timeout(_n, timeout); } void Notification::setCategory(const std::string& category) noexcept { notify_notification_set_category(_n, category.c_str()); } void Notification::setUrgency(Urgency urgency) noexcept { notify_notification_set_urgency(_n, (NotifyUrgency)urgency); } bool Notification::close() const { return notify_notification_close(_n, nullptr); } void Notification::addAction( const std::string& action, const std::string& label, void (*callback)(NotifyNotification*, char*, gpointer), gpointer user_data) noexcept { notify_notification_add_action(_n, action.c_str(), label.c_str(), (NotifyActionCallback)callback, user_data, NULL); } } // namespace notify usbguard-notifier-0.1.0/src/NotifyWrapper.hpp000066400000000000000000000107651435004305000212550ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Zoltán Fridrich */ #ifndef NOTIFY_WRAPPER_HPP #define NOTIFY_WRAPPER_HPP #include #include namespace notify { /** * Notification API. */ class Notify { public: explicit Notify(const std::string& app_name); Notify(const Notify&) = delete; Notify& operator=(const Notify&) = delete; ~Notify(); std::string getAppName() const noexcept; void setAppName(const std::string& app_name); }; enum class Urgency { Low = NOTIFY_URGENCY_LOW, Normal = NOTIFY_URGENCY_NORMAL, Critical = NOTIFY_URGENCY_CRITICAL }; /** * Notification represents a passive pop-up notification. * It can contain summary text, body text, and an icon, as well * as hints specifying how the notification should be presented. * The notification is rendered by a notification daemon and may * present the notification in any number of ways. As such, there * is a clear separation of content and presentation, and this API * enforces that. */ class Notification { public: /** * @brief Creates a new Notification with USBGuard icon. * The summary text is required, but all other parameters are optional. * * @param summary The required summary text. * @param body The optional body text. */ Notification(const std::string& summary, const std::string& body = ""); Notification(const Notification&) = delete; Notification& operator=(const Notification&) = delete; ~Notification() = default; /** * @brief Updates the notification text. * This won't send the update out and display it on the screen. * For that, you will need to call show(). * * @param summary The new required summary text. * @param body The optional body text. * @return True, unless an invalid parameter was passed. */ bool update(const std::string& summary, const std::string& body = ""); /** * @brief Tells the notification server to display * the notification on the screen. * * @return True if successful, false otherwise. */ bool show() const; /** * @brief Sets the timeout of the notification in milliseconds. * Note that the timeout may be ignored by the server. * * @param timeout Timeout in milliseconds. */ void setTimeout(int timeout) noexcept; /** * @brief Sets the category of this notification. * This can be used by the notification server to filter * or display the data in a certain way. * * @param category The category. */ void setCategory(const std::string& category) noexcept; /** * @brief Sets the urgency level of this notification. * * @param urgency The urgency level. * @see Urgency */ void setUrgency(Urgency urgency) noexcept; /** * @brief Adds an action to the notification. * * libnotify uses a C-style callback so this type is needed as an argument. * A static function is needed for this callback to work. * * @param action The action ID. * @param label Human-readable action label. Shown in the notification. * @param callback C-style callback as defined by libnotify. * Callback parameter 'n' should not be used; 'action' and 'user_data' are the same. * @param user_data Optional custom data to pass to callback. */ void addAction( const std::string& action, const std::string& label, void (*callback)(NotifyNotification* n, char* action, gpointer user_data), gpointer user_data) noexcept; /** * @brief Synchronously tells the notification server * to hide the notification on the screen. * * @return True if successful, false otherwise. */ bool close() const; private: NotifyNotification* _n; }; } // namespace notify #endif // NOTIFY_WRAPPER_HPP usbguard-notifier-0.1.0/src/Serializer.cpp000066400000000000000000000056151435004305000205460ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Zoltán Fridrich */ #include "Serializer.hpp" #include namespace usbguardNotifier { static char delim = ';'; bool operator==(const Notification& lhs, const Notification& rhs) { return lhs.event_type == rhs.event_type && lhs.device_id == rhs.device_id && lhs.device_name == rhs.device_name && lhs.target_old == rhs.target_old && lhs.target_new == rhs.target_new && lhs.rule_id == rhs.rule_id && lhs.rule == rhs.rule; } Serializer::Serializer(std::string file_name) : _file_name(std::move(file_name)) {} const std::string& Serializer::getFileName() const noexcept { return _file_name; } void Serializer::setFileName(std::string file_name) noexcept { _file_name = std::move(file_name); } bool Serializer::serialize(const Notification& n) const { std::ofstream out(_file_name, std::ios_base::app); if (!out) { return false; } out << n.event_type << delim << n.device_id << delim << n.device_name << delim << n.target_old << delim << n.target_new << delim << n.rule_id << delim << n.rule << std::endl; return (bool)out; } Notification Serializer::deserialize() const { std::ifstream in(_file_name); if (!in) { throw std::runtime_error("Couldnt open file for deserialization."); } Notification n; if (!deserialize(in, n)) { throw std::runtime_error("Deserialization failed."); } return n; } std::map Serializer::deserializeAll() const { std::ifstream in(_file_name); if (!in) { throw std::runtime_error("Couldnt open file for deserialization."); } std::map v; Notification n; for (unsigned i = 1; deserialize(in, n); ++i) { v.insert({ i, n }); } return v; } bool Serializer::deserialize(std::ifstream& in, Notification& n) const { std::getline(in, n.event_type, delim); in >> n.device_id; in.get(); std::getline(in, n.device_name, delim); std::getline(in, n.target_old, delim); std::getline(in, n.target_new, delim); in >> n.rule_id; in.get(); std::getline(in, n.rule); return (bool)in; } } // namespace usbguardNotifier usbguard-notifier-0.1.0/src/Serializer.hpp000066400000000000000000000061211435004305000205440ustar00rootroot00000000000000/* * Copyright (C) 2019 Red Hat, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, 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, see . * * Author(s): Zoltán Fridrich */ #ifndef SERIALIZER_HPP #define SERIALIZER_HPP #include #include #include namespace usbguardNotifier { /** * Structure representing usbguard notification. */ struct Notification { std::string event_type; uint32_t device_id; std::string device_name; std::string target_old; std::string target_new; uint32_t rule_id; std::string rule; }; bool operator==(const Notification& lhs, const Notification& rhs); /** * Class used to serialize notifications for usbguard-notifier. */ class Serializer { public: /** * @brief Constructs serializer without initializing _file_name */ Serializer() = default; /** * @brief Constructs serializer. * * @param file_name Name of the file on which Serializer operates. */ explicit Serializer(std::string file_name); /** * @brief Returns the name of the file on which Serializer operates. * * @return Name of the file on which Serializer operates. */ const std::string& getFileName() const noexcept; /** * @brief Sets the name of the file on which Serializer operates. * * @param file_name Name of the file on which Serializer operates. */ void setFileName(std::string file_name) noexcept; /** * @brief Serializes given notification into the file. * * @param n Notification to serialize. * @return True if serialization succeeded, false otherwise. */ bool serialize(const Notification& n) const; /** * @brief Deserializes and returns a single notification. * * @return Deserialized notification from the beggining of the file. */ Notification deserialize() const; /** * @brief Deserializes and returns all notifications in a vector. * * @return All notifications from the file. */ std::map deserializeAll() const; private: /** * @brief Core deserialization function. * * @param in Stream from which notification will be deserialized. * @param n Notification to fill. * @return True if deserialization succeeded, false otherwise. */ bool deserialize(std::ifstream& in, Notification& n) const; /** * Name of the file on which Serializer operates. */ std::string _file_name; }; } // namespace usbguardNotifier #endif // SERIALIZER_HPP usbguard-notifier-0.1.0/src/Tests/000077500000000000000000000000001435004305000170245ustar00rootroot00000000000000usbguard-notifier-0.1.0/src/Tests/Makefile.am000066400000000000000000000023031435004305000210560ustar00rootroot00000000000000## ## Copyright (C) 2019 Red Hat, Inc. ## ## This program is free software: you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation, 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, see . ## ## Author(s): Zoltán Fridrich ## AM_CPPFLAGS = \ -I$(top_srcdir)/src \ @catch_CFLAGS@ \ -fPIC EXTRA_DIST = \ $(top_srcdir)/src/ThirdParty/Catch2 TESTS_ENVIRONMENT = \ builddir=$(top_builddir) \ srcdir=$(top_srcdir) \ abs_top_srcdir=$(abs_top_srcdir) TESTS = \ test-unit check_PROGRAMS = \ test-unit test_unit_SOURCES=\ main.cpp \ Unit/test_notifier_cli.cpp \ ../NotifierCLI.hpp \ ../NotifierCLI.cpp \ ../Serializer.hpp \ ../Serializer.cpp usbguard-notifier-0.1.0/src/Tests/Unit/000077500000000000000000000000001435004305000177435ustar00rootroot00000000000000usbguard-notifier-0.1.0/src/Tests/Unit/test_notifier_cli.cpp000066400000000000000000000165071435004305000241650ustar00rootroot00000000000000#include "NotifierCLI.hpp" #include using namespace usbguardNotifier; TEST_CASE("Notifier CLI", "[CLI]") { SECTION("Construct empty") { CLI::map e; CLI cli(e); REQUIRE(cli.getDb().empty()); REQUIRE(cli.getIterator() == cli.getDb().cend()); } CLI::map db = { { 1, {}}, { 2, {}}, { 3, {}}, { 4, {}}, { 5, {}}, { 6, {}}, { 7, {}}, { 8, {}}, { 9, {}} }; CLI cli(db); SECTION("Construct non-empty") { REQUIRE(cli.getDb() == db); REQUIRE(cli.getIterator() == cli.getDb().cbegin()); } SECTION("Jump") { cli.jump("2"); REQUIRE(cli.getIterator() == db.find(2)); cli.jump("0"); REQUIRE(cli.getIterator() == db.find(2)); cli.jump("-1"); REQUIRE(cli.getIterator() == db.find(2)); cli.jump("10"); REQUIRE(cli.getIterator() == db.find(2)); cli.jump("9"); REQUIRE(cli.getIterator() == db.find(9)); cli.jump("9"); REQUIRE(cli.getIterator() == db.find(9)); cli.jump("1"); REQUIRE(cli.getIterator() == db.find(1)); } SECTION("Next") { cli.jump("1"); REQUIRE(cli.getIterator() == cli.getDb().cbegin()); cli.next(""); REQUIRE(cli.getIterator() == db.find(2)); cli.next(""); REQUIRE(cli.getIterator() == db.find(3)); cli.next(""); REQUIRE(cli.getIterator() == db.find(4)); cli.next(""); REQUIRE(cli.getIterator() == db.find(5)); cli.next(""); REQUIRE(cli.getIterator() == db.find(6)); cli.next(""); REQUIRE(cli.getIterator() == db.find(7)); cli.next(""); REQUIRE(cli.getIterator() == db.find(8)); cli.next(""); REQUIRE(cli.getIterator() == db.find(9)); cli.next(""); REQUIRE(cli.getIterator() == db.find(9)); } SECTION("Previous") { cli.jump("9"); REQUIRE(cli.getIterator() == cli.getDb().find(9)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(8)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(7)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(6)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(5)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(4)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(3)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(2)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(1)); cli.previous(""); REQUIRE(cli.getIterator() == db.find(1)); } SECTION("Execute - jump") { cli.execute("jump", "2"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("jump", "0"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("jump", "-1"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("jump", "10"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("jump", "9"); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("jump", "9"); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("jump", "1"); REQUIRE(cli.getIterator() == db.find(1)); } SECTION("Execute - next") { cli.execute("jump", "1"); REQUIRE(cli.getIterator() == cli.getDb().cbegin()); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(3)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(4)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(5)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(6)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(7)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(8)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("next", ""); REQUIRE(cli.getIterator() == db.find(9)); } SECTION("Execute - previous") { cli.execute("jump", "9"); REQUIRE(cli.getIterator() == cli.getDb().find(9)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(8)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(7)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(6)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(5)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(4)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(3)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(1)); cli.execute("previous", ""); REQUIRE(cli.getIterator() == db.find(1)); } SECTION("Execute short - j") { cli.execute("j", "2"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("j", "0"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("j", "-1"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("j", "10"); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("j", "9"); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("j", "9"); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("j", "1"); REQUIRE(cli.getIterator() == db.find(1)); } SECTION("Execute short - n") { cli.execute("j", "1"); REQUIRE(cli.getIterator() == cli.getDb().cbegin()); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(3)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(4)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(5)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(6)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(7)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(8)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(9)); cli.execute("n", ""); REQUIRE(cli.getIterator() == db.find(9)); } SECTION("Execute short - p") { cli.execute("j", "9"); REQUIRE(cli.getIterator() == cli.getDb().find(9)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(8)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(7)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(6)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(5)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(4)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(3)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(2)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(1)); cli.execute("p", ""); REQUIRE(cli.getIterator() == db.find(1)); } } usbguard-notifier-0.1.0/src/Tests/main.cpp000066400000000000000000000000571435004305000204560ustar00rootroot00000000000000#define CATCH_CONFIG_MAIN #include usbguard-notifier-0.1.0/src/ThirdParty/000077500000000000000000000000001435004305000200145ustar00rootroot00000000000000usbguard-notifier-0.1.0/src/ThirdParty/Catch2/000077500000000000000000000000001435004305000211205ustar00rootroot00000000000000usbguard-notifier-0.1.0/usbguard-notifier.service.in000066400000000000000000000002171435004305000225530ustar00rootroot00000000000000[Unit] Description=USBGuard Notifier After=usbguard.service [Service] ExecStart=%bindir%/usbguard-notifier [Install] WantedBy=default.target