You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1198 lines
38 KiB
1198 lines
38 KiB
7 years ago
|
diff --git a/Makefile.am b/Makefile.am
|
||
|
index 37273fb..37508d4 100644
|
||
|
--- a/Makefile.am
|
||
|
+++ b/Makefile.am
|
||
|
@@ -310,18 +310,24 @@ usbguard_daemon_SOURCES=\
|
||
|
src/Daemon/Seccomp.c \
|
||
|
src/Daemon/Seccomp.h \
|
||
|
src/Common/Utility.hpp \
|
||
|
- src/Common/Utility.cpp
|
||
|
+ src/Common/Utility.cpp \
|
||
|
+ src/Daemon/FileAuditBackend.hpp \
|
||
|
+ src/Daemon/FileAuditBackend.cpp \
|
||
|
+ src/Daemon/LinuxAuditBackend.hpp \
|
||
|
+ src/Daemon/LinuxAuditBackend.cpp
|
||
|
|
||
|
usbguard_daemon_CPPFLAGS=\
|
||
|
-fPIE \
|
||
|
$(AM_CPPFLAGS) \
|
||
|
@seccomp_CFLAGS@ \
|
||
|
- @libcapng_CFLAGS@
|
||
|
+ @libcapng_CFLAGS@ \
|
||
|
+ @audit_CFLAGS@
|
||
|
|
||
|
usbguard_daemon_LDADD=\
|
||
|
$(top_builddir)/libusbguard.la \
|
||
|
@seccomp_LIBS@ \
|
||
|
- @libcapng_LIBS@
|
||
|
+ @libcapng_LIBS@ \
|
||
|
+ @audit_LIBS@
|
||
|
|
||
|
EXTRA_DIST +=\
|
||
|
README.md \
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index 6ab0d9b..3298929 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -230,6 +230,14 @@ AC_SUBST([crypto_LIBS])
|
||
|
#
|
||
|
# Check for optional libraries
|
||
|
#
|
||
|
+PKG_CHECK_MODULES([audit], [audit >= 2.7.7],
|
||
|
+[AC_DEFINE([HAVE_LINUX_AUDIT], [1], [Linux Audit API available])
|
||
|
+AC_CHECK_DECLS([audit_encode_nv_string], [], [], [[#include<libaudit.h>]])
|
||
|
+libaudit_summary="system-wide; $audit_LIBS"],
|
||
|
+[AC_MSG_NOTICE([libaudit development files not found! Linux Audit support wille be turned OFF])
|
||
|
+libaudit_summary="not found"]
|
||
|
+)
|
||
|
+
|
||
|
PKG_CHECK_MODULES([seccomp], [libseccomp >= 2.0.0],
|
||
|
[AC_DEFINE([HAVE_SECCOMP], [1], [seccomp API usable])
|
||
|
libseccomp_summary="system-wide; $seccomp_LIBS"],
|
||
|
@@ -752,6 +760,7 @@ echo "## Libraries"
|
||
|
echo
|
||
|
echo " libqb: $libqb_summary"
|
||
|
echo " crypto: $crypto_summary"
|
||
|
+echo " libaudit: $libaudit_summary"
|
||
|
echo " libseccomp: $libseccomp_summary"
|
||
|
echo " libcap-ng: $libcap_ng_summary"
|
||
|
echo " protobuf: $protobuf_summary"
|
||
|
diff --git a/doc/usbguard-daemon.conf.5 b/doc/usbguard-daemon.conf.5
|
||
|
index 476a31e..313f5fb 100644
|
||
|
--- a/doc/usbguard-daemon.conf.5
|
||
|
+++ b/doc/usbguard-daemon.conf.5
|
||
|
@@ -96,6 +96,12 @@ might not match the device after rebooting the system.
|
||
|
.RS
|
||
|
.RE
|
||
|
.TP
|
||
|
+.B \f[B]AuditBackend\f[]=<\f[I]backend\f[]>
|
||
|
+USBGuard audit events log backend.
|
||
|
+Backend should be one of \f[C]FileAudit\f[] or \f[C]LinuxAudit\f[].
|
||
|
+.RS
|
||
|
+.RE
|
||
|
+.TP
|
||
|
.B \f[B]AuditFilePath\f[]=<\f[I]filepath\f[]>
|
||
|
USBGuard audit events log file path.
|
||
|
.RS
|
||
|
diff --git a/doc/usbguard-daemon.conf.5.md b/doc/usbguard-daemon.conf.5.md
|
||
|
index 58ca0ba..ef9ca7c 100644
|
||
|
--- a/doc/usbguard-daemon.conf.5.md
|
||
|
+++ b/doc/usbguard-daemon.conf.5.md
|
||
|
@@ -45,6 +45,9 @@ The **usbguard-daemon.conf** file is loaded by the USBGuard daemon after it pars
|
||
|
**DeviceRulesWithPort**=<*boolean*>
|
||
|
: Generate device specific rules including the "via-port" attribute. This option modifies the behavior of the allowDevice action. When instructed to generate a permanent rule, the action can generate a port specific rule. Because some systems have unstable port numbering, the generated rule might not match the device after rebooting the system.
|
||
|
|
||
|
+**AuditBackend**=<*backend*>
|
||
|
+: USBGuard audit events log backend. Backend should be one of `FileAudit` or `LinuxAudit`.
|
||
|
+
|
||
|
**AuditFilePath**=<*filepath*>
|
||
|
: USBGuard audit events log file path.
|
||
|
|
||
|
diff --git a/src/Common/Utility.cpp b/src/Common/Utility.cpp
|
||
|
index 237acfb..af9585f 100644
|
||
|
--- a/src/Common/Utility.cpp
|
||
|
+++ b/src/Common/Utility.cpp
|
||
|
@@ -365,6 +365,25 @@ namespace usbguard
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ bool hasSuffix(const std::string& value, const std::string& suffix)
|
||
|
+ {
|
||
|
+ if (suffix.size() > value.size()) {
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+ const auto pos = value.size() - suffix.size();
|
||
|
+ const auto cmp = value.compare(pos, suffix.size(), suffix);
|
||
|
+ return cmp == 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ bool hasPrefix(const std::string& value, const std::string& prefix)
|
||
|
+ {
|
||
|
+ if (prefix.size() > value.size()) {
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+ const auto cmp = value.compare(0, prefix.size(), prefix);
|
||
|
+ return cmp == 0;
|
||
|
+ }
|
||
|
+
|
||
|
std::string symlinkPath(const std::string& linkpath, struct stat *st_user)
|
||
|
{
|
||
|
struct stat st = { };
|
||
|
diff --git a/src/Common/Utility.hpp b/src/Common/Utility.hpp
|
||
|
index 54e1ea1..2458930 100644
|
||
|
--- a/src/Common/Utility.hpp
|
||
|
+++ b/src/Common/Utility.hpp
|
||
|
@@ -185,6 +185,12 @@ namespace usbguard
|
||
|
std::string removePrefix(const std::string& prefix, const std::string& value);
|
||
|
|
||
|
/**
|
||
|
+ * Test whether a string value has a prefix/suffix.
|
||
|
+ */
|
||
|
+ bool hasSuffix(const std::string& value, const std::string& suffix);
|
||
|
+ bool hasPrefix(const std::string& value, const std::string& prefix);
|
||
|
+
|
||
|
+ /**
|
||
|
* Read symlink destination.
|
||
|
*/
|
||
|
std::string symlinkPath(const std::string& linkpath, struct stat *st_user = nullptr);
|
||
|
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
|
||
|
index 89d60b3..91c0483 100644
|
||
|
--- a/src/Daemon/Daemon.cpp
|
||
|
+++ b/src/Daemon/Daemon.cpp
|
||
|
@@ -22,6 +22,8 @@
|
||
|
#endif
|
||
|
|
||
|
#include "Daemon.hpp"
|
||
|
+#include "FileAuditBackend.hpp"
|
||
|
+#include "LinuxAuditBackend.hpp"
|
||
|
#include "Common/Utility.hpp"
|
||
|
|
||
|
#include "usbguard/Logger.hpp"
|
||
|
@@ -62,7 +64,8 @@ namespace usbguard
|
||
|
"RestoreControllerDeviceState",
|
||
|
"DeviceManagerBackend",
|
||
|
"IPCAccessControlFiles",
|
||
|
- "AuditFilePath"
|
||
|
+ "AuditFilePath",
|
||
|
+ "AuditBackend"
|
||
|
};
|
||
|
|
||
|
static const std::vector<std::pair<std::string,Daemon::DevicePolicyMethod> > device_policy_method_strings = {
|
||
|
@@ -95,7 +98,8 @@ namespace usbguard
|
||
|
|
||
|
Daemon::Daemon()
|
||
|
: _config(G_config_known_names),
|
||
|
- _ruleset(this)
|
||
|
+ _ruleset(this),
|
||
|
+ _audit(_audit_identity)
|
||
|
{
|
||
|
sigset_t signal_set;
|
||
|
sigfillset(&signal_set);
|
||
|
@@ -245,11 +249,48 @@ namespace usbguard
|
||
|
loadIPCAccessControlFiles(value);
|
||
|
}
|
||
|
|
||
|
- /* AuditFilePath */
|
||
|
- if (_config.hasSettingValue("AuditFilePath")) {
|
||
|
- const std::string value = _config.getSettingValue("AuditFilePath");
|
||
|
- USBGUARD_LOG(Debug) << "Setting AuditFilePath to " << value;
|
||
|
- USBGUARD_LOGGER.setAuditFile(true, value);
|
||
|
+ /* AuditBackend */
|
||
|
+ if (_config.hasSettingValue("AuditBackend")) {
|
||
|
+ const std::string value = _config.getSettingValue("AuditBackend");
|
||
|
+ USBGUARD_LOG(Debug) << "Setting AuditBackend to " << value;
|
||
|
+
|
||
|
+ if (value == "LinuxAudit") {
|
||
|
+ std::unique_ptr<AuditBackend> backend(new LinuxAuditBackend());
|
||
|
+ _audit.setBackend(std::move(backend));
|
||
|
+ }
|
||
|
+ else if (value == "FileAudit") {
|
||
|
+ if (_config.hasSettingValue("AuditFilePath")) {
|
||
|
+ const std::string value = _config.getSettingValue("AuditFilePath");
|
||
|
+ USBGUARD_LOG(Debug) << "Setting AuditFilePath to " << value;
|
||
|
+ USBGUARD_LOGGER.setAuditFile(true, value);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ /* AuditFilePath value is required is AuditBackend is set to FileAudit */
|
||
|
+ throw Exception("Configuration", "AuditBackend", "AuditFilePath not set");
|
||
|
+ }
|
||
|
+
|
||
|
+ std::unique_ptr<AuditBackend> backend(new FileAuditBackend());
|
||
|
+ _audit.setBackend(std::move(backend));
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ throw Exception("Configuration", "AuditBackend", "Invalid value");
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ /*
|
||
|
+ * Left for backwards compatibility. If AuditBackend is NOT set, but
|
||
|
+ * AuditFilePath is, we set the backend to FileAudit automatically.
|
||
|
+ */
|
||
|
+
|
||
|
+ /* AuditFilePath */
|
||
|
+ if (_config.hasSettingValue("AuditFilePath")) {
|
||
|
+ const std::string value = _config.getSettingValue("AuditFilePath");
|
||
|
+ USBGUARD_LOG(Debug) << "Setting AuditFilePath to " << value;
|
||
|
+ USBGUARD_LOGGER.setAuditFile(true, value);
|
||
|
+
|
||
|
+ std::unique_ptr<AuditBackend> backend(new LinuxAuditBackend());
|
||
|
+ _audit.setBackend(std::move(backend));
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
USBGUARD_LOG(Info) << "Configuration loaded successfully.";
|
||
|
@@ -605,7 +646,7 @@ namespace usbguard
|
||
|
USBGUARD_LOG(Trace) << "event=" << DeviceManager::eventTypeToString(event)
|
||
|
<< " device_ptr=" << device.get();
|
||
|
|
||
|
- auto audit_event = Audit::deviceEvent(_audit_identity, device, event);
|
||
|
+ auto audit_event = _audit.deviceEvent(device, event);
|
||
|
|
||
|
std::shared_ptr<const Rule> device_rule = \
|
||
|
device->getDeviceRule(/*with_port*/true,
|
||
|
@@ -648,8 +689,7 @@ namespace usbguard
|
||
|
USBGUARD_LOG(Trace) << "device_ptr=" << device.get()
|
||
|
<< " matched_rule_ptr=" << matched_rule.get();
|
||
|
|
||
|
- auto audit_event = Audit::policyEvent(_audit_identity,
|
||
|
- device, device->getTarget(), matched_rule->getTarget());
|
||
|
+ auto audit_event = _audit.policyEvent(device, device->getTarget(), matched_rule->getTarget());
|
||
|
|
||
|
const Rule::Target target_old = device->getTarget();
|
||
|
std::shared_ptr<Device> device_post = \
|
||
|
diff --git a/src/Daemon/Daemon.hpp b/src/Daemon/Daemon.hpp
|
||
|
index 065deaf..6461f45 100644
|
||
|
--- a/src/Daemon/Daemon.hpp
|
||
|
+++ b/src/Daemon/Daemon.hpp
|
||
|
@@ -129,5 +129,6 @@ namespace usbguard
|
||
|
bool _restore_controller_device_state;
|
||
|
|
||
|
AuditIdentity _audit_identity;
|
||
|
+ Audit _audit;
|
||
|
};
|
||
|
} /* namespace usbguard */
|
||
|
diff --git a/src/Daemon/FileAuditBackend.cpp b/src/Daemon/FileAuditBackend.cpp
|
||
|
new file mode 100644
|
||
|
index 0000000..2d53008
|
||
|
--- /dev/null
|
||
|
+++ b/src/Daemon/FileAuditBackend.cpp
|
||
|
@@ -0,0 +1,47 @@
|
||
|
+//
|
||
|
+// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||
|
+//
|
||
|
+// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+//
|
||
|
+#include "FileAuditBackend.hpp"
|
||
|
+
|
||
|
+#include <Common/Utility.hpp>
|
||
|
+
|
||
|
+namespace usbguard
|
||
|
+{
|
||
|
+ void FileAuditBackend::write(const AuditEvent& event)
|
||
|
+ {
|
||
|
+ std::string message;
|
||
|
+
|
||
|
+ message.append("uid=");
|
||
|
+ message.append(numberToString(event.identity().uid()));
|
||
|
+ message.append(" ");
|
||
|
+
|
||
|
+ message.append("pid=");
|
||
|
+ message.append(numberToString(event.identity().pid()));
|
||
|
+ message.append(" ");
|
||
|
+
|
||
|
+ for (const auto& kv_pair : event.keys()) {
|
||
|
+ message.append(kv_pair.first);
|
||
|
+ message.append("='");
|
||
|
+ message.append(kv_pair.second);
|
||
|
+ message.append("' ");
|
||
|
+ }
|
||
|
+
|
||
|
+ USBGUARD_LOG(Audit) << message;
|
||
|
+ }
|
||
|
+}
|
||
|
+/* vim: set ts=2 sw=2 et */
|
||
|
\ No newline at end of file
|
||
|
diff --git a/src/Daemon/FileAuditBackend.hpp b/src/Daemon/FileAuditBackend.hpp
|
||
|
new file mode 100644
|
||
|
index 0000000..d29a1fe
|
||
|
--- /dev/null
|
||
|
+++ b/src/Daemon/FileAuditBackend.hpp
|
||
|
@@ -0,0 +1,31 @@
|
||
|
+//
|
||
|
+// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||
|
+//
|
||
|
+// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+//
|
||
|
+#pragma once
|
||
|
+
|
||
|
+#include <usbguard/Audit.hpp>
|
||
|
+
|
||
|
+namespace usbguard
|
||
|
+{
|
||
|
+ class FileAuditBackend : public AuditBackend
|
||
|
+ {
|
||
|
+ public:
|
||
|
+ void write(const AuditEvent& event);
|
||
|
+ };
|
||
|
+}
|
||
|
+/* vim: set ts=2 sw=2 et */
|
||
|
\ No newline at end of file
|
||
|
diff --git a/src/Daemon/LinuxAuditBackend.cpp b/src/Daemon/LinuxAuditBackend.cpp
|
||
|
new file mode 100644
|
||
|
index 0000000..cbd4e2c
|
||
|
--- /dev/null
|
||
|
+++ b/src/Daemon/LinuxAuditBackend.cpp
|
||
|
@@ -0,0 +1,305 @@
|
||
|
+//
|
||
|
+// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||
|
+//
|
||
|
+// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+//
|
||
|
+#ifdef HAVE_BUILD_CONFIG_H
|
||
|
+#include <build-config.h>
|
||
|
+#endif
|
||
|
+
|
||
|
+#include "LinuxAuditBackend.hpp"
|
||
|
+
|
||
|
+#include <usbguard/Exception.hpp>
|
||
|
+#include <usbguard/Logger.hpp>
|
||
|
+#include "Common/Utility.hpp"
|
||
|
+#include "Library/Utility.hpp"
|
||
|
+
|
||
|
+#include <stdexcept>
|
||
|
+
|
||
|
+#if defined(HAVE_LINUX_AUDIT)
|
||
|
+#include <libaudit.h>
|
||
|
+
|
||
|
+#ifndef AUDIT_USER_DEVICE
|
||
|
+#define AUDIT_USER_DEVICE 1137 /* User space hotplug device changes */
|
||
|
+#endif
|
||
|
+
|
||
|
+#if !defined(HAVE_DECL_AUDIT_ENCODE_NV_STRING)
|
||
|
+#ifndef _GNU_SOURCE
|
||
|
+#define _GNU_SOURCE 1
|
||
|
+#endif
|
||
|
+
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+ /*
|
||
|
+ * Audit message encoding functions based on:
|
||
|
+ * https://github.com/linux-audit/audit-userspace/blob/f7cd4d6/lib/audit_logging.c#L125
|
||
|
+ */
|
||
|
+
|
||
|
+ /*
|
||
|
+ * This function checks a string to see if it needs encoding.
|
||
|
+ * It returns true if needed and false if not.
|
||
|
+ */
|
||
|
+ static bool audit_value_needs_encoding(const char *str, unsigned int size)
|
||
|
+ {
|
||
|
+ if (str == NULL) {
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (unsigned int i = 0; i < size; i++) {
|
||
|
+ // we don't test for > 0x7f because str[] is signed.
|
||
|
+ if (str[i] == '"' || str[i] < 0x21 || str[i] == 0x7F) {
|
||
|
+ return true;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * This function does encoding of "untrusted" names just like the kernel
|
||
|
+ */
|
||
|
+ static char *audit_encode_value(char *final, const char *buf, unsigned int size)
|
||
|
+ {
|
||
|
+ char *ptr = final;
|
||
|
+ const char *hex = "0123456789ABCDEF";
|
||
|
+
|
||
|
+ if (final == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ if (buf == NULL) {
|
||
|
+ *final = 0;
|
||
|
+ return final;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (unsigned int i = 0; i < size; i++) {
|
||
|
+ *ptr++ = hex[(buf[i] & 0xF0)>>4]; /* Upper nibble */
|
||
|
+ *ptr++ = hex[buf[i] & 0x0F]; /* Lower nibble */
|
||
|
+ }
|
||
|
+ *ptr = 0;
|
||
|
+ return final;
|
||
|
+ }
|
||
|
+
|
||
|
+ static char *audit_encode_nv_string(const char *name, const char *value, unsigned int vlen)
|
||
|
+ {
|
||
|
+ char *str = nullptr;
|
||
|
+ if (vlen == 0 && value) {
|
||
|
+ vlen = ::strlen(value);
|
||
|
+ }
|
||
|
+ if (value && audit_value_needs_encoding(value, vlen)) {
|
||
|
+ char *tmp = reinterpret_cast<char*>(::malloc(2*vlen + 1));
|
||
|
+ if (tmp) {
|
||
|
+ audit_encode_value(tmp, value, vlen);
|
||
|
+ if (::asprintf(&str, "%s=%s", name, tmp) < 0) {
|
||
|
+ str = nullptr;
|
||
|
+ }
|
||
|
+ free(tmp);
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ str = nullptr;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ if (::asprintf(&str, "%s=\"%s\"", name, value ? value : "?") < 0) {
|
||
|
+ str = nullptr;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return str;
|
||
|
+ }
|
||
|
+#endif /* HAVE_DECL_AUDIT_ENCODE_NV_STRING */
|
||
|
+#endif /* HAVE_LINUX_AUDIT */
|
||
|
+
|
||
|
+namespace usbguard
|
||
|
+{
|
||
|
+#if defined(HAVE_LINUX_AUDIT)
|
||
|
+ static std::string encodeMessageNVPair(const std::string& key, const std::string& value)
|
||
|
+ {
|
||
|
+ std::unique_ptr<char, FreeDeleter> encoded_cstr(audit_encode_nv_string(key.c_str(), value.c_str(), value.size()));
|
||
|
+ std::string encoded(encoded_cstr.get());
|
||
|
+ return encoded;
|
||
|
+ }
|
||
|
+
|
||
|
+ static void appendToMessage(std::string& message, const std::string& key, const std::string& value)
|
||
|
+ {
|
||
|
+ if (message.size() > 0) {
|
||
|
+ message.append(" ");
|
||
|
+ }
|
||
|
+ message.append(encodeMessageNVPair(key, value));
|
||
|
+ }
|
||
|
+
|
||
|
+ static std::string translateTypeValue(const std::string& value)
|
||
|
+ {
|
||
|
+ if (hasPrefix(value, "Policy.Device.")) {
|
||
|
+ /* device policy events */
|
||
|
+ if (hasSuffix(value, "Update")) {
|
||
|
+ return "changed-authorization-state-for";
|
||
|
+ }
|
||
|
+ throw std::runtime_error("LinuxAuditBackend: unexpected Policy.Device event");
|
||
|
+ }
|
||
|
+ else if (hasPrefix(value, "Device.")) {
|
||
|
+ /* device events */
|
||
|
+ if (hasSuffix(value, "Present")) {
|
||
|
+ return "discovered-device";
|
||
|
+ }
|
||
|
+ if (hasSuffix(value, "Insert")) {
|
||
|
+ return "inserted-device";
|
||
|
+ }
|
||
|
+ if (hasSuffix(value, "Update")) {
|
||
|
+ return "updated-device";
|
||
|
+ }
|
||
|
+ if (hasSuffix(value, "Remove")) {
|
||
|
+ return "removed-device";
|
||
|
+ }
|
||
|
+ throw std::runtime_error("LinuxAuditBackend: unexpected Device event");
|
||
|
+ }
|
||
|
+ else if (hasPrefix(value, "Policy.")) {
|
||
|
+ /* rule set modification events */
|
||
|
+ if (hasSuffix(value, "Insert")) {
|
||
|
+ return "inserted-policy-rule";
|
||
|
+ }
|
||
|
+ if (hasSuffix(value, "Update")) {
|
||
|
+ return "updated-policy-rule";
|
||
|
+ }
|
||
|
+ if (hasSuffix(value, "Remove")) {
|
||
|
+ return "removed-policy-rule";
|
||
|
+ }
|
||
|
+ throw std::runtime_error("LinuxAuditBackend: unexpected Policy event");
|
||
|
+ }
|
||
|
+
|
||
|
+ throw std::runtime_error("LinuxAuditBackend: unexpected type= key value");
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
+ LinuxAuditBackend::LinuxAuditBackend()
|
||
|
+ {
|
||
|
+#if defined(HAVE_LINUX_AUDIT)
|
||
|
+ USBGUARD_LOG(Debug) << "Opening Linux Audit socket";
|
||
|
+ if ((_audit_fd = audit_open()) < 0) {
|
||
|
+ throw ErrnoException("LinuxAuditBackend", "audit_open", errno);
|
||
|
+ }
|
||
|
+#else
|
||
|
+ (void)_audit_fd;
|
||
|
+ throw std::runtime_error("LinuxAuditBackend: not supported");
|
||
|
+#endif
|
||
|
+ }
|
||
|
+
|
||
|
+ LinuxAuditBackend::~LinuxAuditBackend()
|
||
|
+ {
|
||
|
+#if defined(HAVE_LINUX_AUDIT)
|
||
|
+ USBGUARD_LOG(Debug) << "Closing Linux Audit socket";
|
||
|
+ audit_close(_audit_fd);
|
||
|
+#endif
|
||
|
+ }
|
||
|
+
|
||
|
+ void LinuxAuditBackend::write(const AuditEvent& event)
|
||
|
+ {
|
||
|
+#if defined(HAVE_LINUX_AUDIT)
|
||
|
+ std::string message;
|
||
|
+ /*
|
||
|
+ * Linux Audit event result
|
||
|
+ * 0 = failed
|
||
|
+ * 1 = success
|
||
|
+ */
|
||
|
+ int result = 0;
|
||
|
+ auto kvals = event.keys();
|
||
|
+
|
||
|
+ std::string audit_key;
|
||
|
+ std::string audit_value;
|
||
|
+
|
||
|
+ if (kvals.count("type") > 0) {
|
||
|
+ audit_key = "op";
|
||
|
+ audit_value = translateTypeValue(kvals["type"]);
|
||
|
+ appendToMessage(message, audit_key, audit_value);
|
||
|
+ kvals.erase("type");
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ throw std::runtime_error("missing required type field in the audit event");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (kvals.count("result") > 0) {
|
||
|
+ if (kvals["result"] == "SUCCESS") {
|
||
|
+ result = 1;
|
||
|
+ }
|
||
|
+ kvals.erase("result");
|
||
|
+ }
|
||
|
+ else {
|
||
|
+ throw std::runtime_error("missing required result field in the audit event");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (kvals.count("device.system_name") > 0) {
|
||
|
+ audit_key = "device";
|
||
|
+ audit_value = kvals["device.system_name"];
|
||
|
+ appendToMessage(message, audit_key, audit_value);
|
||
|
+ kvals.erase("device.system_name");
|
||
|
+ }
|
||
|
+
|
||
|
+ if (kvals.count("rule") > 0) {
|
||
|
+ audit_key = "rule";
|
||
|
+ audit_value = kvals["rule"];
|
||
|
+ appendToMessage(message, audit_key, audit_value);
|
||
|
+ kvals.erase("rule");
|
||
|
+ }
|
||
|
+
|
||
|
+ for (const auto& kv_pair : kvals) {
|
||
|
+ const std::string& key = kv_pair.first;
|
||
|
+ const std::string& value = kv_pair.second;
|
||
|
+
|
||
|
+ audit_key.clear();
|
||
|
+ audit_value.clear();
|
||
|
+
|
||
|
+ if (key == "device.rule") {
|
||
|
+ audit_key = "device_rule";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ else if (key == "device.rule.new") {
|
||
|
+ audit_key = "device_rule";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ else if (key == "target") {
|
||
|
+ audit_key = "target";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ else if (key == "target.new") {
|
||
|
+ audit_key = "target";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ else if (key == "rule.id") {
|
||
|
+ audit_key = "rule_id";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ else if (key == "rule.new") {
|
||
|
+ audit_key = "rule";
|
||
|
+ audit_value = value;
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * Skip appending the key=value pair to the message, if the
|
||
|
+ * audit_key string is empty. This is used to skip key=value
|
||
|
+ * pairs that we don't want to include in the Linux Audit trail.
|
||
|
+ */
|
||
|
+ if (!audit_key.empty()) {
|
||
|
+ appendToMessage(message, audit_key, audit_value);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ USBGUARD_LOG(Debug) << "Writing Linux Audit message: " << message;
|
||
|
+ audit_log_user_message(_audit_fd, AUDIT_USER_DEVICE, message.c_str(),
|
||
|
+ /*hostname=*/nullptr, /*addr=*/nullptr, /*tty=*/nullptr, result);
|
||
|
+#else
|
||
|
+ (void)event;
|
||
|
+ throw std::runtime_error("LinuxAuditBackend::write: not supported");
|
||
|
+#endif
|
||
|
+ }
|
||
|
+}
|
||
|
+/* vim: set ts=2 sw=2 et */
|
||
|
\ No newline at end of file
|
||
|
diff --git a/src/Daemon/LinuxAuditBackend.hpp b/src/Daemon/LinuxAuditBackend.hpp
|
||
|
new file mode 100644
|
||
|
index 0000000..647c045
|
||
|
--- /dev/null
|
||
|
+++ b/src/Daemon/LinuxAuditBackend.hpp
|
||
|
@@ -0,0 +1,37 @@
|
||
|
+//
|
||
|
+// Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.
|
||
|
+//
|
||
|
+// Authors: Daniel Kopecek <dkopecek@redhat.com>
|
||
|
+//
|
||
|
+#pragma once
|
||
|
+
|
||
|
+#include <usbguard/Audit.hpp>
|
||
|
+
|
||
|
+namespace usbguard
|
||
|
+{
|
||
|
+ class LinuxAuditBackend : public AuditBackend
|
||
|
+ {
|
||
|
+ public:
|
||
|
+ LinuxAuditBackend();
|
||
|
+ ~LinuxAuditBackend();
|
||
|
+
|
||
|
+ void write(const AuditEvent& event);
|
||
|
+
|
||
|
+ private:
|
||
|
+ int _audit_fd{-1};
|
||
|
+ };
|
||
|
+}
|
||
|
+/* vim: set ts=2 sw=2 et */
|
||
|
\ No newline at end of file
|
||
|
diff --git a/src/Library/UEventDeviceManager.cpp b/src/Library/UEventDeviceManager.cpp
|
||
|
index bdf4ad0..2f44ff0 100644
|
||
|
--- a/src/Library/UEventDeviceManager.cpp
|
||
|
+++ b/src/Library/UEventDeviceManager.cpp
|
||
|
@@ -149,6 +149,11 @@ namespace usbguard {
|
||
|
return hub_interface.appliesTo(getInterfaceTypes()[0]);
|
||
|
}
|
||
|
|
||
|
+ std::string UEventDevice::getSystemName() const
|
||
|
+ {
|
||
|
+ return getSysPath();
|
||
|
+ }
|
||
|
+
|
||
|
void UEventDevice::parseUSBDescriptor(USBDescriptorParser* parser, const USBDescriptor* descriptor_raw, USBDescriptor* descriptor_out)
|
||
|
{
|
||
|
USBGUARD_LOG(Trace);
|
||
|
diff --git a/src/Library/UEventDeviceManager.hpp b/src/Library/UEventDeviceManager.hpp
|
||
|
index b7adb60..7de6951 100644
|
||
|
--- a/src/Library/UEventDeviceManager.hpp
|
||
|
+++ b/src/Library/UEventDeviceManager.hpp
|
||
|
@@ -49,6 +49,7 @@ namespace usbguard {
|
||
|
SysFSDevice& sysfsDevice();
|
||
|
const std::string& getSysPath() const;
|
||
|
bool isController() const override;
|
||
|
+ std::string getSystemName() const override;
|
||
|
|
||
|
private:
|
||
|
void parseUSBDescriptor(USBDescriptorParser* parser, const USBDescriptor* descriptor_raw, USBDescriptor* descriptor_out) override;
|
||
|
diff --git a/src/Library/public/usbguard/Audit.cpp b/src/Library/public/usbguard/Audit.cpp
|
||
|
index e692733..60bbd1b 100644
|
||
|
--- a/src/Library/public/usbguard/Audit.cpp
|
||
|
+++ b/src/Library/public/usbguard/Audit.cpp
|
||
|
@@ -41,73 +41,120 @@ namespace usbguard
|
||
|
_pid = pid;
|
||
|
}
|
||
|
|
||
|
+ uid_t AuditIdentity::uid() const
|
||
|
+ {
|
||
|
+ return _uid;
|
||
|
+ }
|
||
|
+
|
||
|
+ pid_t AuditIdentity::pid() const
|
||
|
+ {
|
||
|
+ return _pid;
|
||
|
+ }
|
||
|
+
|
||
|
std::string AuditIdentity::toString() const
|
||
|
{
|
||
|
std::string identity_string;
|
||
|
|
||
|
identity_string.append("{ uid=");
|
||
|
- identity_string.append(numberToString(_uid));
|
||
|
+ identity_string.append(numberToString(uid()));
|
||
|
identity_string.append(" pid=");
|
||
|
- identity_string.append(numberToString(_pid));
|
||
|
+ identity_string.append(numberToString(pid()));
|
||
|
identity_string.append(" }");
|
||
|
|
||
|
return identity_string;
|
||
|
}
|
||
|
|
||
|
- AuditEvent::AuditEvent(const AuditIdentity& identity)
|
||
|
- : _confirmed(false),
|
||
|
- _identity(identity)
|
||
|
+ AuditEvent::AuditEvent(const AuditIdentity& identity, std::shared_ptr<AuditBackend>& backend)
|
||
|
+ : _commited(false),
|
||
|
+ _identity(identity),
|
||
|
+ _backend(backend)
|
||
|
{
|
||
|
-
|
||
|
}
|
||
|
|
||
|
AuditEvent::AuditEvent(AuditEvent&& event)
|
||
|
- : _confirmed(event._confirmed),
|
||
|
+ : _commited(event._commited),
|
||
|
_identity(std::move(event._identity)),
|
||
|
- _message(std::move(event._message))
|
||
|
+ _backend(std::move(event._backend)),
|
||
|
+ _keys(std::move(event._keys))
|
||
|
{
|
||
|
- event.setConfirmed(true);
|
||
|
+ /*
|
||
|
+ * Mark the source event as commited so that
|
||
|
+ * when it gets destructed, it won't be commited
|
||
|
+ * to the backend.
|
||
|
+ */
|
||
|
+ event.setCommited(true);
|
||
|
}
|
||
|
|
||
|
AuditEvent::~AuditEvent()
|
||
|
{
|
||
|
- if (!_confirmed) {
|
||
|
+ /*
|
||
|
+ * If the event was not commited explicitly, assume
|
||
|
+ * that that the result is a failure.
|
||
|
+ */
|
||
|
+ if (!_commited) {
|
||
|
failure();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- void AuditEvent::confirm(const std::string& result)
|
||
|
+ void AuditEvent::commit(const std::string& result)
|
||
|
{
|
||
|
- USBGUARD_LOG(Audit) << "result=" << result \
|
||
|
- << " identity=" << _identity.toString() \
|
||
|
- << " " << _message;
|
||
|
- setConfirmed(true);
|
||
|
+ setKey("result", result);
|
||
|
+ _backend->commit(*this);
|
||
|
+ setCommited(true);
|
||
|
}
|
||
|
|
||
|
void AuditEvent::success()
|
||
|
{
|
||
|
- confirm("SUCCESS");
|
||
|
+ commit("SUCCESS");
|
||
|
}
|
||
|
|
||
|
void AuditEvent::failure()
|
||
|
{
|
||
|
- confirm("FAILURE");
|
||
|
+ commit("FAILURE");
|
||
|
+ }
|
||
|
+
|
||
|
+ const AuditIdentity& AuditEvent::identity() const
|
||
|
+ {
|
||
|
+ return _identity;
|
||
|
}
|
||
|
|
||
|
- void AuditEvent::setConfirmed(bool state)
|
||
|
+ const AuditEvent::Keys& AuditEvent::keys() const
|
||
|
{
|
||
|
- _confirmed = state;
|
||
|
+ return _keys;
|
||
|
}
|
||
|
|
||
|
- std::string& AuditEvent::refMessage()
|
||
|
+ void AuditEvent::setCommited(bool state)
|
||
|
{
|
||
|
- return _message;
|
||
|
+ _commited = state;
|
||
|
+ }
|
||
|
+
|
||
|
+ void AuditEvent::setKey(const std::string& key, const std::string& value)
|
||
|
+ {
|
||
|
+ _keys.emplace(key, value);
|
||
|
+ }
|
||
|
+
|
||
|
+ AuditBackend::AuditBackend()
|
||
|
+ {
|
||
|
+ }
|
||
|
+
|
||
|
+ AuditBackend::~AuditBackend()
|
||
|
+ {
|
||
|
+ }
|
||
|
+
|
||
|
+ void AuditBackend::commit(const AuditEvent& event)
|
||
|
+ {
|
||
|
+ std::unique_lock<std::mutex> lock(_mutex);
|
||
|
+ write(event);
|
||
|
}
|
||
|
|
||
|
Audit::Audit(const AuditIdentity& identity)
|
||
|
: _identity(identity)
|
||
|
{
|
||
|
+ }
|
||
|
|
||
|
+ void Audit::setBackend(std::unique_ptr<AuditBackend> backend)
|
||
|
+ {
|
||
|
+ _backend = std::shared_ptr<AuditBackend>(std::move(backend));
|
||
|
}
|
||
|
|
||
|
AuditEvent Audit::policyEvent(std::shared_ptr<Rule> rule, Policy::EventType event)
|
||
|
@@ -140,116 +187,74 @@ namespace usbguard
|
||
|
return deviceEvent(_identity, new_device, old_device);
|
||
|
}
|
||
|
|
||
|
- AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> rule, Policy::EventType event)
|
||
|
+ AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> rule, Policy::EventType event_type)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Policy.";
|
||
|
- message += Policy::eventTypeToString(event);
|
||
|
-
|
||
|
- message += " rule.id=";
|
||
|
- message += numberToString(rule->getRuleID());
|
||
|
-
|
||
|
- message += " rule='";
|
||
|
- message += rule->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Policy.") + Policy::eventTypeToString(event_type));
|
||
|
+ event.setKey("rule.id", numberToString(rule->getRuleID()));
|
||
|
+ event.setKey("rule", rule->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
|
||
|
AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> new_rule, std::shared_ptr<Rule> old_rule)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Policy.";
|
||
|
- message += Policy::eventTypeToString(Policy::EventType::Update);
|
||
|
-
|
||
|
- message += " rule.id=";
|
||
|
- message += numberToString(old_rule->getRuleID());
|
||
|
-
|
||
|
- message += " rule.old='";
|
||
|
- message += old_rule->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- message += " rule.new='";
|
||
|
- message += new_rule->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Policy.") + Policy::eventTypeToString(Policy::EventType::Update));
|
||
|
+ event.setKey("rule.id", numberToString(old_rule->getRuleID()));
|
||
|
+ event.setKey("rule.old", old_rule->toString());
|
||
|
+ event.setKey("rule.new", new_rule->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
|
||
|
- AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Policy::EventType event)
|
||
|
+ AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Policy::EventType event_type)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Policy.Device.";
|
||
|
- message += Policy::eventTypeToString(event);
|
||
|
-
|
||
|
- message += " target=";
|
||
|
- message += Rule::targetToString(device->getTarget());
|
||
|
-
|
||
|
- message += " device='";
|
||
|
- message += device->getDeviceRule()->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Policy.Device.") + Policy::eventTypeToString(event_type));
|
||
|
+ event.setKey("target", Rule::targetToString(device->getTarget()));
|
||
|
+ event.setKey("device.system_name", device->getSystemName());
|
||
|
+ event.setKey("device.rule", device->getDeviceRule()->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
|
||
|
AuditEvent Audit::policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Rule::Target old_target, Rule::Target new_target)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Policy.Device.";
|
||
|
- message += Policy::eventTypeToString(Policy::EventType::Update);
|
||
|
-
|
||
|
- message += " target.old=";
|
||
|
- message += Rule::targetToString(old_target);
|
||
|
-
|
||
|
- message += " target.new=";
|
||
|
- message += Rule::targetToString(new_target);
|
||
|
-
|
||
|
- message += " device='";
|
||
|
- message += device->getDeviceRule()->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Policy.Device.") + Policy::eventTypeToString(Policy::EventType::Update));
|
||
|
+ event.setKey("target.old", Rule::targetToString(old_target));
|
||
|
+ event.setKey("target.new", Rule::targetToString(new_target));
|
||
|
+ event.setKey("device.system_name", device->getSystemName());
|
||
|
+ event.setKey("device.rule", device->getDeviceRule()->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
|
||
|
- AuditEvent Audit::deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, DeviceManager::EventType event)
|
||
|
+ AuditEvent Audit::deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, DeviceManager::EventType event_type)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Device.";
|
||
|
- message += DeviceManager::eventTypeToString(event);
|
||
|
-
|
||
|
- message += " device='";
|
||
|
- message += device->getDeviceRule()->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Device.") + DeviceManager::eventTypeToString(event_type));
|
||
|
+ event.setKey("device.system_name", device->getSystemName());
|
||
|
+ event.setKey("device.rule", device->getDeviceRule()->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
|
||
|
AuditEvent Audit::deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> new_device, std::shared_ptr<Device> old_device)
|
||
|
{
|
||
|
- AuditEvent audit_event(identity);
|
||
|
- auto& message = audit_event.refMessage();
|
||
|
-
|
||
|
- message += "type=Device.";
|
||
|
- message += DeviceManager::eventTypeToString(DeviceManager::EventType::Update);
|
||
|
-
|
||
|
- message += " device.old='";
|
||
|
- message += old_device->getDeviceRule()->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- message += " device.new='";
|
||
|
- message += new_device->getDeviceRule()->toString();
|
||
|
- message += "'";
|
||
|
-
|
||
|
- return audit_event;
|
||
|
+ AuditEvent event(identity, _backend);
|
||
|
+
|
||
|
+ event.setKey("type", std::string("Device.") + DeviceManager::eventTypeToString(DeviceManager::EventType::Update));
|
||
|
+ event.setKey("device.system_name", new_device->getSystemName());
|
||
|
+ event.setKey("device.rule.old", old_device->getDeviceRule()->toString());
|
||
|
+ event.setKey("device.rule.new", new_device->getDeviceRule()->toString());
|
||
|
+
|
||
|
+ return event;
|
||
|
}
|
||
|
} /* namespace usbguard */
|
||
|
diff --git a/src/Library/public/usbguard/Audit.hpp b/src/Library/public/usbguard/Audit.hpp
|
||
|
index 398d4c2..991a451 100644
|
||
|
--- a/src/Library/public/usbguard/Audit.hpp
|
||
|
+++ b/src/Library/public/usbguard/Audit.hpp
|
||
|
@@ -27,6 +27,8 @@
|
||
|
|
||
|
#include <string>
|
||
|
#include <memory>
|
||
|
+#include <mutex>
|
||
|
+#include <unordered_map>
|
||
|
|
||
|
#include <unistd.h>
|
||
|
#include <sys/types.h>
|
||
|
@@ -39,16 +41,24 @@ namespace usbguard
|
||
|
AuditIdentity();
|
||
|
AuditIdentity(uid_t uid, pid_t pid);
|
||
|
|
||
|
+ uid_t uid() const;
|
||
|
+ pid_t pid() const;
|
||
|
+
|
||
|
std::string toString() const;
|
||
|
+
|
||
|
private:
|
||
|
uid_t _uid;
|
||
|
pid_t _pid;
|
||
|
};
|
||
|
|
||
|
+ class AuditBackend;
|
||
|
+
|
||
|
class DLL_PUBLIC AuditEvent
|
||
|
{
|
||
|
- AuditEvent(const AuditIdentity& identity);
|
||
|
+ AuditEvent(const AuditIdentity& identity, std::shared_ptr<AuditBackend>& backend);
|
||
|
public:
|
||
|
+ using Keys = std::unordered_map<std::string,std::string>;
|
||
|
+
|
||
|
AuditEvent(AuditEvent&& event);
|
||
|
AuditEvent(const AuditEvent& event) = delete;
|
||
|
~AuditEvent();
|
||
|
@@ -56,23 +66,43 @@ namespace usbguard
|
||
|
void success();
|
||
|
void failure();
|
||
|
|
||
|
+ const AuditIdentity& identity() const;
|
||
|
+ const Keys& keys() const;
|
||
|
+
|
||
|
private:
|
||
|
- void confirm(const std::string& result);
|
||
|
- void setConfirmed(bool state);
|
||
|
- std::string& refMessage();
|
||
|
+ void commit(const std::string& result);
|
||
|
+ void setCommited(bool state);
|
||
|
+ void setKey(const std::string& key, const std::string& value);
|
||
|
|
||
|
- bool _confirmed;
|
||
|
+ bool _commited;
|
||
|
+
|
||
|
AuditIdentity _identity;
|
||
|
- std::string _message;
|
||
|
+ std::shared_ptr<AuditBackend> _backend;
|
||
|
+ Keys _keys;
|
||
|
|
||
|
friend class Audit;
|
||
|
};
|
||
|
|
||
|
+ class DLL_PUBLIC AuditBackend
|
||
|
+ {
|
||
|
+ public:
|
||
|
+ AuditBackend();
|
||
|
+ virtual ~AuditBackend();
|
||
|
+
|
||
|
+ virtual void write(const AuditEvent& event) = 0;
|
||
|
+ void commit(const AuditEvent& event);
|
||
|
+
|
||
|
+ private:
|
||
|
+ std::mutex _mutex;
|
||
|
+ };
|
||
|
+
|
||
|
class DLL_PUBLIC Audit
|
||
|
{
|
||
|
public:
|
||
|
Audit(const AuditIdentity& identity);
|
||
|
|
||
|
+ void setBackend(std::unique_ptr<AuditBackend> backend);
|
||
|
+
|
||
|
AuditEvent policyEvent(std::shared_ptr<Rule> rule, Policy::EventType event);
|
||
|
AuditEvent policyEvent(std::shared_ptr<Rule> new_rule, std::shared_ptr<Rule> old_rule);
|
||
|
AuditEvent policyEvent(std::shared_ptr<Device> device, Policy::EventType event);
|
||
|
@@ -94,10 +124,10 @@ namespace usbguard
|
||
|
* - what: append, remove, update
|
||
|
* - update: old, new
|
||
|
*/
|
||
|
- static AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> rule, Policy::EventType event);
|
||
|
- static AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> new_rule, std::shared_ptr<Rule> old_rule);
|
||
|
- static AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Policy::EventType event);
|
||
|
- static AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Rule::Target old_target, Rule::Target new_target);
|
||
|
+ AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> rule, Policy::EventType event);
|
||
|
+ AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Rule> new_rule, std::shared_ptr<Rule> old_rule);
|
||
|
+ AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Policy::EventType event);
|
||
|
+ AuditEvent policyEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, Rule::Target old_target, Rule::Target new_target);
|
||
|
|
||
|
/*
|
||
|
* Audit device changes:
|
||
|
@@ -111,10 +141,11 @@ namespace usbguard
|
||
|
* - what: insert, remove, authorization target
|
||
|
* - change: old, new
|
||
|
*/
|
||
|
- static AuditEvent deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, DeviceManager::EventType event);
|
||
|
- static AuditEvent deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> new_device, std::shared_ptr<Device> old_device);
|
||
|
+ AuditEvent deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> device, DeviceManager::EventType event);
|
||
|
+ AuditEvent deviceEvent(const AuditIdentity& identity, std::shared_ptr<Device> new_device, std::shared_ptr<Device> old_device);
|
||
|
|
||
|
private:
|
||
|
AuditIdentity _identity;
|
||
|
+ std::shared_ptr<AuditBackend> _backend;
|
||
|
};
|
||
|
} /* namespace usbguard */
|
||
|
diff --git a/src/Library/public/usbguard/Device.hpp b/src/Library/public/usbguard/Device.hpp
|
||
|
index d5a8130..f8dbb8d 100644
|
||
|
--- a/src/Library/public/usbguard/Device.hpp
|
||
|
+++ b/src/Library/public/usbguard/Device.hpp
|
||
|
@@ -78,6 +78,7 @@ namespace usbguard {
|
||
|
const std::vector<USBInterfaceType>& getInterfaceTypes() const;
|
||
|
|
||
|
virtual bool isController() const = 0;
|
||
|
+ virtual std::string getSystemName() const = 0;
|
||
|
|
||
|
void loadDeviceDescriptor(USBDescriptorParser* parser, const USBDescriptor* descriptor);
|
||
|
void loadConfigurationDescriptor(USBDescriptorParser* parser, const USBDescriptor* descriptor);
|
||
|
diff --git a/usbguard-daemon.conf.in b/usbguard-daemon.conf.in
|
||
|
index 5e39e7b..bb98276 100644
|
||
|
--- a/usbguard-daemon.conf.in
|
||
|
+++ b/usbguard-daemon.conf.in
|
||
|
@@ -155,6 +155,18 @@ IPCAccessControlFiles=%sysconfdir%/usbguard/IPCAccessControl.d/
|
||
|
DeviceRulesWithPort=false
|
||
|
|
||
|
#
|
||
|
+# USBGuard Audit events log backend
|
||
|
+#
|
||
|
+# One of:
|
||
|
+#
|
||
|
+# * FileAudit - Log audit events into a file specified by
|
||
|
+# AuditFilePath setting (see below)
|
||
|
+# * LinuxAudit - Log audit events using the Linux Audit
|
||
|
+# subsystem (using audit_log_user_message)
|
||
|
+#
|
||
|
+AuditBackend=FileAudit
|
||
|
+
|
||
|
+#
|
||
|
# USBGuard audit events log file path.
|
||
|
#
|
||
|
-AuditFilePath=%localstatedir%/log/usbguard/usbguard-audit.log
|
||
|
+AuditFilePath=%localstatedir%/log/usbguard/usbguard-audit.log
|
||
|
\ No newline at end of file
|