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.
472 lines
14 KiB
472 lines
14 KiB
diff --git a/Makefile.am b/Makefile.am |
|
index 1852983..b7aa1a3 100644 |
|
--- a/Makefile.am |
|
+++ b/Makefile.am |
|
@@ -15,6 +15,7 @@ |
|
## along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
## |
|
## Authors: Daniel Kopecek <dkopecek@redhat.com> |
|
+## Jiri Vymazal <jvymazal@redhat.com> |
|
## |
|
SUBDIRS=src/Tests/ |
|
|
|
diff --git a/doc/usbguard-daemon.8 b/doc/usbguard-daemon.8 |
|
index 18c72fe..dfdb285 100644 |
|
--- a/doc/usbguard-daemon.8 |
|
+++ b/doc/usbguard-daemon.8 |
|
@@ -1,4 +1,4 @@ |
|
-.\" Automatically generated by Pandoc 1.17.0.3 |
|
+.\" Automatically generated by Pandoc 1.19.1 |
|
.\" |
|
.TH "USBGUARD\-DAEMON" "8" "June 2016" "" "" |
|
.hy |
|
@@ -25,6 +25,11 @@ Enable debugging messages in the log. |
|
.RS |
|
.RE |
|
.TP |
|
+.B \f[B]\-f\f[] |
|
+Enable classical daemon behavior (fork at start, sysV compliant). |
|
+.RS |
|
+.RE |
|
+.TP |
|
.B \f[B]\-s\f[] |
|
Log to syslog. |
|
.RS |
|
@@ -41,7 +46,8 @@ Log to a file at \f[I]path\f[]. |
|
.RE |
|
.TP |
|
.B \f[B]\-p\f[] <\f[I]path\f[]> |
|
-Write PID to a file at \f[I]path\f[]. |
|
+Write PID to a file at \f[I]path\f[] (default: |
|
+\f[I]/var/run/usbguard.pid\f[]). |
|
.RS |
|
.RE |
|
.TP |
|
diff --git a/doc/usbguard-daemon.8.md b/doc/usbguard-daemon.8.md |
|
index 3e2fcaf..581613d 100644 |
|
--- a/doc/usbguard-daemon.8.md |
|
+++ b/doc/usbguard-daemon.8.md |
|
@@ -19,6 +19,9 @@ The **usbguard-daemon** is the main component of the USBGuard software framework |
|
**-d** |
|
: Enable debugging messages in the log. |
|
|
|
+**-f** |
|
+: Enable classical daemon behavior (fork at start, sysV compliant). |
|
+ |
|
**-s** |
|
: Log to syslog. |
|
|
|
@@ -29,7 +32,7 @@ The **usbguard-daemon** is the main component of the USBGuard software framework |
|
: Log to a file at *path*. |
|
|
|
**-p** <*path*> |
|
-: Write PID to a file at *path*. |
|
+: Write PID to a file at *path* (default: */var/run/usbguard.pid*). |
|
|
|
**-c** <*path*> |
|
: Load configuration from a file at *path* (default: */etc/usbguard/usbguard-daemon.conf*). |
|
diff --git a/src/Common/Utility.cpp b/src/Common/Utility.cpp |
|
index f84d2a8..237acfb 100644 |
|
--- a/src/Common/Utility.cpp |
|
+++ b/src/Common/Utility.cpp |
|
@@ -42,56 +42,6 @@ |
|
namespace usbguard |
|
{ |
|
|
|
- void daemonize() |
|
- { |
|
- const ::pid_t pid = fork(); |
|
- |
|
- switch(pid) { |
|
- case 0: /* child */ |
|
- break; |
|
- case -1: /* error */ |
|
- ::exit(EXIT_FAILURE); |
|
- default: /* parent */ |
|
- ::exit(EXIT_SUCCESS); |
|
- } |
|
- // |
|
- // Decouple from parent environment |
|
- // - chdir to / |
|
- // - create new process session |
|
- // - reset umask |
|
- // - cleanup file descriptors |
|
- // - ??? |
|
- // - consider using libdaemon |
|
- // |
|
- if (::chdir("/") != 0) { |
|
- ::exit(EXIT_FAILURE); |
|
- } |
|
- const ::pid_t sid = ::setsid(); |
|
- if (sid != 0) { |
|
- ::exit(EXIT_FAILURE); |
|
- } |
|
- ::umask(::umask(077)|022); |
|
- struct rlimit rlim; |
|
- if (::getrlimit(RLIMIT_NOFILE, &rlim) != 0) { |
|
- ::exit(EXIT_FAILURE); |
|
- } |
|
- const int maxfd = (rlim.rlim_max == RLIM_INFINITY ? 1024 : rlim.rlim_max); |
|
- for (int fd = 0; fd < maxfd; ++fd) { |
|
- ::close(fd); |
|
- } |
|
- return; |
|
- } |
|
- |
|
- bool writePID(const std::string& filepath) |
|
- { |
|
- std::ofstream pidstream(filepath, std::ios_base::trunc); |
|
- if (!pidstream) { |
|
- return false; |
|
- } |
|
- pidstream << numberToString(getpid()) << std::endl; |
|
- return true; |
|
- } |
|
- |
|
static void runCommandExecChild(const std::string& path, const std::vector<std::string>& args) |
|
{ |
|
struct rlimit rlim; |
|
diff --git a/src/Common/Utility.hpp b/src/Common/Utility.hpp |
|
index f722b22..54e1ea1 100644 |
|
--- a/src/Common/Utility.hpp |
|
+++ b/src/Common/Utility.hpp |
|
@@ -41,25 +41,6 @@ |
|
namespace usbguard |
|
{ |
|
/** |
|
- * Create a background process. |
|
- * |
|
- * Performs the following actions: |
|
- * 1) fork a new process (parent process exists with 0) |
|
- * 2) chdir to / |
|
- * 3) creates a new process session |
|
- * 4) resets umask |
|
- * 5) closes all file descriptors |
|
- * 6) Reinitialize logging for the child |
|
- */ |
|
- void daemonize(void); |
|
- |
|
- /** |
|
- * Writes the current PID to a file at filepath. |
|
- * Returns true on success, otherwise returns false. |
|
- */ |
|
- bool writePID(const std::string& filepath); |
|
- |
|
- /** |
|
* Wrappers for the __builtin_expect function. |
|
*/ |
|
#if defined(__GNUC__) |
|
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp |
|
index b317c85..2a9a37c 100644 |
|
--- a/src/Daemon/Daemon.cpp |
|
+++ b/src/Daemon/Daemon.cpp |
|
@@ -15,6 +15,7 @@ |
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
// |
|
// Authors: Daniel Kopecek <dkopecek@redhat.com> |
|
+// Jiri Vymazal <jvymazal@redhat.com> |
|
// |
|
#ifdef HAVE_BUILD_CONFIG_H |
|
#include <build-config.h> |
|
@@ -27,6 +28,8 @@ |
|
#include "usbguard/RuleParser.hpp" |
|
#include "usbguard/Audit.hpp" |
|
|
|
+#include <array> |
|
+ |
|
#include <sys/select.h> |
|
#include <sys/time.h> |
|
#include <sys/types.h> |
|
@@ -112,6 +115,8 @@ namespace usbguard |
|
|
|
_device_rules_with_port = false; |
|
_restore_controller_device_state = false; |
|
+ |
|
+ pid_fd = -1; |
|
} |
|
|
|
Daemon::~Daemon() |
|
@@ -402,6 +407,10 @@ namespace usbguard |
|
} |
|
} while(!exit_loop); |
|
|
|
+ if (pid_fd != -1) { |
|
+ lockf(pid_fd, F_ULOCK, 0); |
|
+ close(pid_fd); |
|
+ } |
|
IPCServer::stop(); |
|
_dm->stop(); |
|
USBGUARD_LOG(Trace) << "Leaving main loop."; |
|
@@ -411,6 +420,73 @@ namespace usbguard |
|
{ |
|
} |
|
|
|
+ void Daemon::daemonize(const std::string &pid_file) |
|
+ { |
|
+ USBGUARD_LOG(Trace) << "Starting daemonization"; |
|
+ |
|
+ pid_t pid = 0; |
|
+ pid_t original_pid = getpid(); |
|
+ |
|
+ sigset_t mask; |
|
+ sigemptyset(&mask); |
|
+ sigaddset(&mask, SIGUSR1); |
|
+ sigprocmask(SIG_BLOCK, &mask, nullptr); |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0); |
|
+ if (pid > 0) { |
|
+ constexpr int timeout_val = 5; |
|
+ struct timespec timeout {timeout_val,0}; |
|
+ const time_t start = time(nullptr); |
|
+ siginfo_t info; |
|
+ do { |
|
+ const int signum = sigtimedwait(&mask, &info, &timeout); |
|
+ if (signum == SIGUSR1 && info.si_signo == SIGUSR1 && info.si_pid == pid) { |
|
+ USBGUARD_LOG(Trace) << "Finished daemonization"; |
|
+ exit(EXIT_SUCCESS); |
|
+ } |
|
+ if (signum == -1 && errno == EAGAIN) { |
|
+ break; /* timed out */ |
|
+ } |
|
+ timeout.tv_sec = timeout_val - difftime(time(nullptr), start); /* avoid potentially endless loop */ |
|
+ } while(true); |
|
+ throw Exception("Deamonize", "signal", "Waiting on pid file write timeout!"); |
|
+ } |
|
+ |
|
+ /* Now we are forked */ |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", setsid() < 0); |
|
+ signal(SIGCHLD, SIG_IGN); |
|
+ |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid_fd = open(pid_file.c_str(), O_RDWR|O_CREAT, 0640)) < 0); |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (lockf(pid_fd, F_TLOCK, 0)) < 0); |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (pid = fork()) < 0); |
|
+ if (pid > 0) { |
|
+ try { |
|
+ std::string pid_str = std::to_string(pid); |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", write(pid_fd, pid_str.c_str(), pid_str.size()) != static_cast<ssize_t>(pid_str.size())); |
|
+ kill(original_pid, SIGUSR1); |
|
+ exit(EXIT_SUCCESS); |
|
+ } |
|
+ catch(...) { |
|
+ kill(pid, SIGKILL); |
|
+ throw; |
|
+ } |
|
+ } |
|
+ |
|
+ /* Now we are forked 2nd time */ |
|
+ umask(0047); /* no need for world-accessible or executable files */ |
|
+ chdir("/"); |
|
+ const std::array<int,3> std_fds {{STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO}}; |
|
+ int fd_null; |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (fd_null = open("/dev/null", O_RDWR)) < 0); |
|
+ /* We do not need to close all fds because there is only logging open at this point */ |
|
+ for (auto fd : std_fds) { |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", close(fd)); |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (dup2(fd_null, fd)) < 0); |
|
+ } |
|
+ close(fd_null); |
|
+ |
|
+ USBGUARD_SYSCALL_THROW("Daemonize", (lockf(pid_fd, F_LOCK, 0)) < 0); |
|
+ } |
|
+ |
|
uint32_t Daemon::assignID() |
|
{ |
|
return _ruleset.assignID(); |
|
diff --git a/src/Daemon/Daemon.hpp b/src/Daemon/Daemon.hpp |
|
index cfd02d9..065deaf 100644 |
|
--- a/src/Daemon/Daemon.hpp |
|
+++ b/src/Daemon/Daemon.hpp |
|
@@ -15,6 +15,7 @@ |
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
// |
|
// Authors: Daniel Kopecek <dkopecek@redhat.com> |
|
+// Jiri Vymazal <jvymazal@redhat.com> |
|
// |
|
#pragma once |
|
#ifdef HAVE_BUILD_CONFIG_H |
|
@@ -72,6 +73,8 @@ namespace usbguard |
|
void run(); |
|
/* Stop the daemon */ |
|
void quit(); |
|
+ /* Handle process daemonization */ |
|
+ void daemonize(const std::string& pid_file); |
|
|
|
uint32_t assignID(); |
|
uint32_t upsertRule(const std::string& match_spec, const std::string& rule_spec, bool parent_insensitive = false); |
|
@@ -112,6 +115,8 @@ namespace usbguard |
|
ConfigFile _config; |
|
RuleSet _ruleset; |
|
|
|
+ int pid_fd; |
|
+ |
|
std::string _device_manager_backend; |
|
std::shared_ptr<DeviceManager> _dm; |
|
|
|
diff --git a/src/Daemon/main.cpp b/src/Daemon/main.cpp |
|
index 869c2e2..4b9b351 100644 |
|
--- a/src/Daemon/main.cpp |
|
+++ b/src/Daemon/main.cpp |
|
@@ -15,6 +15,7 @@ |
|
// along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
// |
|
// Authors: Daniel Kopecek <dkopecek@redhat.com> |
|
+// Jiri Vymazal <jvymazal@redhat.com> |
|
// |
|
#ifdef HAVE_BUILD_CONFIG_H |
|
#include <build-config.h> |
|
@@ -37,9 +38,13 @@ |
|
static void setupCapabilities(void); |
|
#endif |
|
|
|
+#ifndef USBGUARD_PID_FILE |
|
+#define USBGUARD_PID_FILE "/var/run/usbguard.pid" |
|
+#endif |
|
+ |
|
using namespace usbguard; |
|
|
|
-const char * const G_optstring = "dskl:p:c:hWC"; |
|
+const char * const G_optstring = "dfskl:p:c:hWC"; |
|
|
|
static void printUsage(std::ostream& stream, const char *arg0) |
|
{ |
|
@@ -47,6 +52,7 @@ static void printUsage(std::ostream& stream, const char *arg0) |
|
stream << "Usage: " << filenameFromPath(std::string(arg0), true) << " [OPTIONS]" << std::endl; |
|
stream << std::endl; |
|
stream << " -d Enable debugging messages in the log." << std::endl; |
|
+ stream << " -f Enable classical daemon forking behavior." << std::endl; |
|
stream << " -s Log to syslog." << std::endl; |
|
stream << " -k Log to console." << std::endl; |
|
stream << " -l <path> Log to a file at `path'." << std::endl; |
|
@@ -68,8 +74,9 @@ int main(int argc, char *argv[]) |
|
bool log_file = false; |
|
bool use_seccomp_whitelist = false; |
|
bool drop_capabilities = false; |
|
+ bool daemonize = false; |
|
std::string log_file_path; |
|
- std::string pid_file; |
|
+ std::string pid_file = USBGUARD_PID_FILE; |
|
std::string conf_file = "/etc/usbguard/usbguard-daemon.conf"; |
|
int opt; |
|
|
|
@@ -79,6 +86,9 @@ int main(int argc, char *argv[]) |
|
case 'd': |
|
debug_mode = true; |
|
break; |
|
+ case 'f': |
|
+ daemonize = true; |
|
+ break; |
|
case 's': |
|
log_syslog = true; |
|
break; |
|
@@ -144,6 +154,13 @@ int main(int argc, char *argv[]) |
|
if (!conf_file.empty()) { |
|
daemon.loadConfiguration(conf_file); |
|
} |
|
+ if (daemonize) { |
|
+ if (log_console && !log_syslog && !log_file) { |
|
+ USBGUARD_LOG(Warning) << "You have selected to fork and log only to \ |
|
+ console, nothing will be logged after forking!"; |
|
+ } |
|
+ daemon.daemonize(pid_file); |
|
+ } |
|
daemon.run(); |
|
ret = EXIT_SUCCESS; |
|
} |
|
diff --git a/src/Tests/Makefile.am b/src/Tests/Makefile.am |
|
index 7d93474..a952d18 100644 |
|
--- a/src/Tests/Makefile.am |
|
+++ b/src/Tests/Makefile.am |
|
@@ -40,6 +40,7 @@ EXTRA_DIST=\ |
|
$(top_srcdir)/src/Tests/UseCase/001_cli_policy.sh \ |
|
$(top_srcdir)/src/Tests/UseCase/002_cli_devices.sh \ |
|
$(top_srcdir)/src/Tests/UseCase/003_cli_devices_dummy.sh \ |
|
+ $(top_srcdir)/src/Tests/UseCase/004_daemonize.sh \ |
|
$(top_srcdir)/src/Tests/UseCase/DummyDevices |
|
|
|
LOG_DRIVER=\ |
|
@@ -62,7 +63,8 @@ TESTS=\ |
|
UseCase/000_executable.sh \ |
|
UseCase/001_cli_policy.sh \ |
|
UseCase/002_cli_devices.sh \ |
|
- UseCase/003_cli_devices_dummy.sh |
|
+ UseCase/003_cli_devices_dummy.sh \ |
|
+ UseCase/004_daemonize.sh |
|
|
|
check_PROGRAMS=\ |
|
test-unit \ |
|
diff --git a/src/Tests/UseCase/004_daemonize.sh b/src/Tests/UseCase/004_daemonize.sh |
|
new file mode 100755 |
|
index 0000000..d59dad1 |
|
--- /dev/null |
|
+++ b/src/Tests/UseCase/004_daemonize.sh |
|
@@ -0,0 +1,55 @@ |
|
+#!/bin/bash |
|
+# |
|
+# |
|
+# Copyright (C) 2016 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: Jiri Vymazal <jvymazal@redhat.com> |
|
+# |
|
+# Test whether the binaries are executable as expected (no linker errors, etc.) |
|
+# |
|
+source "${USBGUARD_TESTLIB_BASH}" || exit 129 |
|
+ |
|
+# TODO? Move to testlib |
|
+export USBGUARD_TESTLIB_TMPDIR="$(mktemp -d --tmpdir usbguard-test.XXXXXX)" |
|
+ |
|
+export config_path="${USBGUARD_TESTLIB_TMPDIR}/daemon.conf" |
|
+export pidfile_path="${USBGUARD_TESTLIB_TMPDIR}/usbguard.pid" |
|
+export logfile="${USBGUARD_TESTLIB_TMPDIR}/daemon.log" |
|
+ |
|
+function test_cli_daemonize() |
|
+{ |
|
+ sleep 5 |
|
+ |
|
+ if [ ! -f "$pidfile_path" ]; then |
|
+ echo "Test error: PID file for usbguard not present" |
|
+ exit 1 |
|
+ fi |
|
+ |
|
+ if [ ! `pgrep usbguard` == `cat $pidfile_path` ]; then |
|
+ echo "Test error: PID of usbguard daemon not present in PID file" |
|
+ exit 1 |
|
+ fi |
|
+} |
|
+ |
|
+cat > "$config_path" <<EOF |
|
+EOF |
|
+ |
|
+schedule "${USBGUARD_DAEMON} -f -p $pidfile_path -d -P -l $logfile -c $config_path" :service |
|
+schedule "test_cli_daemonize" |
|
+execute 20 |
|
+retval=$? |
|
+cat $pidfile_path | xargs kill -9 |
|
+exit $retval |
|
diff --git a/usbguard.service.in b/usbguard.service.in |
|
index 5bed4e6..f862d3b 100644 |
|
--- a/usbguard.service.in |
|
+++ b/usbguard.service.in |
|
@@ -4,8 +4,9 @@ Wants=systemd-udevd.service local-fs.target |
|
Documentation=man:usbguard-daemon(8) |
|
|
|
[Service] |
|
-Type=simple |
|
-ExecStart=%sbindir%/usbguard-daemon -k -c %sysconfdir%/usbguard/usbguard-daemon.conf |
|
+Type=forking |
|
+PIDFile=/var/run/usbguard.pid |
|
+ExecStart=%sbindir%/usbguard-daemon -f -s -c %sysconfdir%/usbguard/usbguard-daemon.conf |
|
Restart=on-failure |
|
|
|
[Install]
|
|
|