fix(quarantine): prevent directory moves

This commit is contained in:
specialworld83 2026-07-25 16:29:04 +02:00
commit 1c5dfc1a84
28 changed files with 2100 additions and 268 deletions

View file

@ -542,8 +542,8 @@ target_include_directories(BastionGuard
)
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2340,7 +2340,6 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -1,2 +1,2 @@
version=2.0
build=20260411
version=2.0.1
build=20260726

View file

@ -672,8 +672,8 @@ target_include_directories(BastionGuard
)
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2398,7 +2398,6 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

2
debian/changelog vendored
View file

@ -1,4 +1,4 @@
bastionguard (2.0-1) stable; urgency=low
bastionguard (2.0.1-1) stable; urgency=low
* Debian package.

View file

@ -1,4 +1,4 @@
bastionguard (2.0-1ubuntu24.04.1) noble; urgency=low
bastionguard (2.0.1-1ubuntu24.04.1) noble; urgency=low
* Ubuntu 24.04 (Noble) package.

View file

@ -1,4 +1,4 @@
bastionguard (2.0-1ubuntu25.10) questing; urgency=low
bastionguard (2.0.1-1ubuntu25.10) questing; urgency=low
* Ubuntu 25.10 (Questing Quokka) package.

View file

@ -1,4 +1,4 @@
bastionguard (2.0-1ubuntu26.04) questing; urgency=low
bastionguard (2.0.1-1ubuntu26.04) questing; urgency=low
* Ubuntu 26.04 (Resolute Raccoon) package.

View file

@ -19,7 +19,7 @@
#
Name: bastionguard
Version: 2.0
Version: 2.0.1
Release: 1%{?dist}
Summary: BastionGuard Security Platform
@ -27,7 +27,8 @@ Provides: bastionguard = %{version}-%{release}
Obsoletes: bastionguard < %{version}-%{release}
License: GPLv3
URL: https://git.bastionguard.eu/specialworld83/BastionGuard
URL: https://bastionguard.eu
Vendor: BastionGuard
Source0: %{name}-%{version}.tar.gz
%global debug_package %{nil}

View file

@ -208,6 +208,28 @@ find_package(PkgConfig REQUIRED)
find_package(Gettext REQUIRED)
include(GNUInstallDirs)
include(cmake/BastionGuardInit.cmake)
bastionguard_detect_init_system(BG_INIT_SYSTEM)
set(BG_SERVICECTL_PATH "/usr/libexec/bastionguard/bastionguard-service")
set(BASTIONGUARD_DINIT_SYSTEM_DIR "/etc/dinit.d" CACHE PATH
"Dinit system service description directory")
set(BASTIONGUARD_DINIT_USER_DIR "/usr/lib/dinit.d/user" CACHE PATH
"Dinit user service description directory")
set(BG_DINIT_ENABLE_DIR
"${BASTIONGUARD_DINIT_SYSTEM_DIR}/bastionguard.d")
configure_file(
data/init/common/bastionguard-init-config.in
"${CMAKE_CURRENT_BINARY_DIR}/bastionguard-init-config"
@ONLY
NEWLINE_STYLE UNIX
)
message(STATUS "BastionGuard init backend: ${BG_INIT_SYSTEM}")
add_compile_definitions(
BASTIONGUARD_INIT_SYSTEM=\"${BG_INIT_SYSTEM}\"
BASTIONGUARD_SERVICECTL_PATH=\"${BG_SERVICECTL_PATH}\"
)
find_package(Threads REQUIRED)
# ============================================================
# BastionGuard – RPATH centralizzato
@ -234,29 +256,25 @@ endfunction()
# ======================
# libsystemd / sd-bus
# ======================
pkg_check_modules(SYSTEMD REQUIRED libsystemd)
if (SYSTEMD_FOUND)
message(STATUS "✔ libsystemd trovato: ${SYSTEMD_VERSION}")
include_directories(${SYSTEMD_INCLUDE_DIRS})
link_directories(${SYSTEMD_LIBRARY_DIRS})
add_definitions(${SYSTEMD_CFLAGS_OTHER})
else()
message(FATAL_ERROR "❌ libsystemd non trovato. Installa libsystemd-dev")
endif()
# ======================
# systemd (sd-bus) — necessario su Debian/Ubuntu recenti (DSO missing)
# ======================
# sd-bus is used by the StatusNotifierItem implementation, not for service
# management. It remains optional on OpenRC, SysVinit and Dinit systems.
pkg_check_modules(SYSTEMD QUIET libsystemd)
if (SYSTEMD_FOUND)
if(SYSTEMD_FOUND)
message(STATUS "✔ libsystemd trovato: ${SYSTEMD_VERSION}")
include_directories(${SYSTEMD_INCLUDE_DIRS})
bg_link_directories(${SYSTEMD_LIBRARY_DIRS})
add_definitions(${SYSTEMD_CFLAGS_OTHER})
add_compile_definitions(BASTIONGUARD_HAS_SDBUS=1)
set(BG_TRAYICON_SOURCE src/TrayIcon.cpp)
else()
message(WARNING "⚠ libsystemd non trovato (libsystemd-dev). Alcune feature potrebbero non compilare.")
message(WARNING "libsystemd non trovato: tray SNI disabilitata; init ${BG_INIT_SYSTEM} resta supportato")
add_compile_definitions(BASTIONGUARD_HAS_SDBUS=0)
set(BG_TRAYICON_SOURCE src/TrayIconStub.cpp)
endif()
function(bg_link_systemd tgt)
if (SYSTEMD_FOUND AND TARGET ${tgt})
if(SYSTEMD_FOUND AND TARGET ${tgt})
target_include_directories(${tgt} PRIVATE ${SYSTEMD_INCLUDE_DIRS})
target_link_directories(${tgt} PRIVATE ${SYSTEMD_LIBRARY_DIRS})
target_link_libraries(${tgt} PRIVATE ${SYSTEMD_LIBRARIES})
@ -291,8 +309,12 @@ else()
message(STATUS "✔ rsync trovato: ${RSYNC_EXECUTABLE}")
endif()
# Option to control whether systemd services are enabled / started at install time.
option(ENABLE_SYSTEMD_SERVICES "Enable and start systemd services at install time" OFF)
# Option to control whether init services are enabled / started at install time.
option(ENABLE_INIT_SERVICES "Enable and start BastionGuard init services at install time" OFF)
option(ENABLE_SYSTEMD_SERVICES "Deprecated alias for ENABLE_INIT_SERVICES" OFF)
if(ENABLE_SYSTEMD_SERVICES)
set(ENABLE_INIT_SERVICES ON)
endif()
install(DIRECTORY data/
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/BastionGuard/data
@ -658,7 +680,7 @@ target_link_libraries(firewall
set(BastionGuard_SOURCES
src/main.cpp
src/MainWindow.cpp
src/TrayIcon.cpp
${BG_TRAYICON_SOURCE}
src/Backend.cpp
src/DashboardPage.cpp
src/ScanPage.cpp
@ -714,8 +736,8 @@ target_include_directories(BastionGuard
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -737,7 +759,6 @@ target_link_libraries(BastionGuard
OpenSSL::SSL
OpenSSL::Crypto
)
target_link_options(BastionGuard PRIVATE -lsystemd)
bg_set_rpath(BastionGuard)
bg_link_systemd(BastionGuard)
if(ENABLE_CEF)
@ -1343,14 +1364,15 @@ install(TARGETS BastionGuard-privacyd RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR
# Demone USB (BastionGuard-usbd)
# ======================
# Trova libsystemd
find_package(PkgConfig REQUIRED)
pkg_check_modules(SYSTEMD REQUIRED libsystemd)
if(SYSTEMD_FOUND)
set(BG_USBD_BUS_SOURCE src/usb/BastionGuard-usbd.cpp)
else()
set(BG_USBD_BUS_SOURCE src/usb/BastionGuard-usbd-gdbus.cpp)
endif()
set(USBD_SOURCES
src/usb/BastionGuard-usbd.cpp
${BG_USBD_BUS_SOURCE}
src/usb/LiveScanDialog.cpp
)
add_executable(BastionGuard-usbd ${USBD_SOURCES})
@ -1367,7 +1389,7 @@ target_link_libraries(BastionGuard-usbd
${GIOMM_LIBRARIES}
${SIGC_LIBRARIES}
${UDEV_LIBRARIES}
${SYSTEMD_LIBRARIES} # <── FIX CRITICO
${SYSTEMD_LIBRARIES}
)
bg_set_rpath(BastionGuard-usbd)
target_compile_definitions(BastionGuard-usbd PRIVATE
@ -1657,7 +1679,7 @@ endif()
# ======================
# BastionGuard-mailproxy — proxy SMTP utente
# Gira come systemctl --user, senza privilegi root
# Gira come servizio utente, senza privilegi root
# ======================
add_executable(BastionGuard-mailproxy
@ -1689,11 +1711,7 @@ install(TARGETS BastionGuard-mailproxy
WORLD_READ WORLD_EXECUTE
)
# Installa il service file systemd --user
install(FILES
data/service/BastionGuard-mailproxy.service
DESTINATION /usr/lib/systemd/user
)
# Il service file viene installato nella sezione init-system centralizzata.
# ============================================================
# BastionGuard WebUI
@ -1912,13 +1930,15 @@ if(ENABLE_BASTIONGUARD_SECURE_CONNECTION)
--sysconfdir=/etc
--localedir=share/locale
--buildtype=release
-Dinstall_systemd_service=false
--reconfigure
BUILD_COMMAND
${MESON_EXECUTABLE} compile -C "${BG_SC_BINARY_DIR}"
INSTALL_COMMAND
${MESON_EXECUTABLE} install -C "${BG_SC_BINARY_DIR}" --destdir "${BG_SC_INSTALL_DIR}"
${CMAKE_COMMAND} -E rm -rf "${BG_SC_INSTALL_DIR}"
COMMAND ${MESON_EXECUTABLE} install -C "${BG_SC_BINARY_DIR}" --destdir "${BG_SC_INSTALL_DIR}"
BUILD_ALWAYS 1
@ -2350,7 +2370,9 @@ if (INSTALL_NGINX_DEFAULTS)
message(STATUS \"[NGINX] Testo configurazione...\")
execute_process(COMMAND nginx -t RESULT_VARIABLE nginx_test)
if(nginx_test EQUAL 0)
execute_process(COMMAND systemctl restart nginx)
execute_process(
COMMAND ${BG_SERVICECTL_PATH} --system restart nginx.service
)
message(STATUS \"[NGINX] ✅ Configurazione valida, Nginx riavviato.\")
else()
message(WARNING \"[NGINX] ⚠ Test configurazione fallito. Controlla con: sudo nginx -t\")
@ -2429,38 +2451,196 @@ endif()
# Services
# ======================
# opzione per abilitare automaticamente le user units durante 'cmake --install' (default OFF)
option(ENABLE_USER_AGENT_AUTO "Attempt to enable systemd --user unit for logged-in users at install time" OFF)
# opzione per abilitare automaticamente i servizi utente durante install
option(ENABLE_USER_AGENT_AUTO "Attempt to enable user services for logged-in users at install time" OFF)
# install system units (system-wide)
# Dispatcher e supervisori comuni a tutti i backend.
install(PROGRAMS
data/init/common/bastionguard-service
data/init/common/bastionguard-supervise
data/init/common/bastionguard-periodic
data/init/common/bastionguard-sanesecurity-update
DESTINATION /usr/libexec/bastionguard
)
install(FILES
data/service/BastionGuard-phishing-scanner.service
data/service/BastionGuard-phishing-updater.service
data/service/BastionGuard-phishing-updater.timer
data/service/BastionGuard-ransomware-realtime.service
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
DESTINATION /usr/lib/systemd/system
"${CMAKE_CURRENT_BINARY_DIR}/bastionguard-init-config"
DESTINATION /usr/libexec/bastionguard
)
# install user units (systemd --user services)
install(FILES
data/service/BastionGuard-useragent.service
data/service/BastionGuard-privacyd.service
data/service/BastionGuard-ransomware-alert.service
data/service/BastionGuard-ransomware-realtime-alert.service
data/service/BastionGuard-ransomware-scanner.service
data/service/BastionGuard-pacd.service
data/service/BastionGuard-mailproxy.service
data/service/BastionGuard-user-session-watch.service
DESTINATION /usr/lib/systemd/user
)
if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
install(FILES
data/service/BastionGuard-phishing-scanner.service
data/service/BastionGuard-phishing-updater.service
data/service/BastionGuard-phishing-updater.timer
data/service/BastionGuard-ransomware-realtime.service
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
DESTINATION /usr/lib/systemd/system
)
if(ENABLE_CEF AND ENABLE_CEF_DAEMON)
install(FILES data/service/BastionGuard-cef.service
if(ENABLE_BASTIONGUARD_SECURE_CONNECTION)
install(FILES
thirdparty/bastionguard-secure-connection/dist/bsc-daemon.service
DESTINATION /usr/lib/systemd/system
)
endif()
install(FILES
data/service/BastionGuard-useragent.service
data/service/BastionGuard-privacyd.service
data/service/BastionGuard-ransomware-alert.service
data/service/BastionGuard-ransomware-realtime-alert.service
data/service/BastionGuard-ransomware-scanner.service
data/service/BastionGuard-pacd.service
data/service/BastionGuard-mailproxy.service
data/service/BastionGuard-user-session-watch.service
DESTINATION /usr/lib/systemd/user
)
if(ENABLE_CEF AND ENABLE_CEF_DAEMON)
install(FILES data/service/BastionGuard-cef.service
DESTINATION /usr/lib/systemd/user
)
endif()
elseif(BG_INIT_SYSTEM STREQUAL "OPENRC")
function(bg_install_openrc_service service_name)
install(PROGRAMS data/init/openrc/bastionguard-openrc-service
DESTINATION /etc/init.d
RENAME "${service_name}")
endfunction()
bg_install_openrc_service(BastionGuard-phishing-scanner)
bg_install_openrc_service(BastionGuard-phishing-updater)
bg_install_openrc_service(BastionGuard-phishing-updater-timer)
bg_install_openrc_service(BastionGuard-ransomware-realtime)
bg_install_openrc_service(bastionguard-sanesecurity)
bg_install_openrc_service(bastionguard-sanesecurity-timer)
bg_install_openrc_service(BastionGuard-usbd)
bg_install_openrc_service(clamav-clamonacc)
if(ENABLE_BASTIONGUARD_SECURE_CONNECTION)
bg_install_openrc_service(bsc-daemon)
endif()
install(FILES data/init/common/bastionguard-user-services.desktop
DESTINATION /etc/xdg/autostart)
elseif(BG_INIT_SYSTEM STREQUAL "SYSVINIT")
function(bg_install_sysv_service service_name)
set(BG_SYSV_SERVICE_NAME "${service_name}")
set(_generated_service
"${CMAKE_CURRENT_BINARY_DIR}/init/sysvinit/${service_name}")
configure_file(
data/init/sysvinit/bastionguard-sysv-service.in
"${_generated_service}"
@ONLY
NEWLINE_STYLE UNIX
)
install(PROGRAMS "${_generated_service}"
DESTINATION /etc/init.d)
endfunction()
bg_install_sysv_service(BastionGuard-phishing-scanner)
bg_install_sysv_service(BastionGuard-phishing-updater)
bg_install_sysv_service(BastionGuard-phishing-updater-timer)
bg_install_sysv_service(BastionGuard-ransomware-realtime)
bg_install_sysv_service(bastionguard-sanesecurity)
bg_install_sysv_service(bastionguard-sanesecurity-timer)
bg_install_sysv_service(BastionGuard-usbd)
bg_install_sysv_service(clamav-clamonacc)
if(ENABLE_BASTIONGUARD_SECURE_CONNECTION)
bg_install_sysv_service(bsc-daemon)
endif()
install(FILES data/init/common/bastionguard-user-services.desktop
DESTINATION /etc/xdg/autostart)
elseif(BG_INIT_SYSTEM STREQUAL "DINIT")
install(PROGRAMS
data/init/dinit/bastionguard-dinit-run
data/init/dinit/bastionguard-dinit-user-run
DESTINATION /usr/libexec/bastionguard
)
set(_generated_dinit_root
"${CMAKE_CURRENT_BINARY_DIR}/init/dinit/bastionguard")
configure_file(
data/init/dinit/bastionguard-dinit-root.in
"${_generated_dinit_root}"
@ONLY
NEWLINE_STYLE UNIX
)
install(FILES "${_generated_dinit_root}"
DESTINATION "${BASTIONGUARD_DINIT_SYSTEM_DIR}")
install(DIRECTORY DESTINATION "${BG_DINIT_ENABLE_DIR}")
function(bg_install_dinit_service service_name service_type restart_policy)
set(BG_DINIT_SERVICE_NAME "${service_name}")
set(BG_DINIT_SERVICE_TYPE "${service_type}")
set(BG_DINIT_SERVICE_RESTART "${restart_policy}")
if(service_type STREQUAL "process")
set(BG_DINIT_SERVICE_RESTART_OPTIONS
"restart-delay = 5\nrestart-limit-count = 0")
else()
set(BG_DINIT_SERVICE_RESTART_OPTIONS "")
endif()
set(_generated_service
"${CMAKE_CURRENT_BINARY_DIR}/init/dinit/system/${service_name}")
configure_file(
data/init/dinit/bastionguard-dinit-service.in
"${_generated_service}"
@ONLY
NEWLINE_STYLE UNIX
)
install(FILES "${_generated_service}"
DESTINATION "${BASTIONGUARD_DINIT_SYSTEM_DIR}")
endfunction()
bg_install_dinit_service(BastionGuard-phishing-scanner process on-failure)
bg_install_dinit_service(BastionGuard-phishing-updater process false)
bg_install_dinit_service(BastionGuard-phishing-updater-timer process on-failure)
bg_install_dinit_service(BastionGuard-ransomware-realtime process on-failure)
bg_install_dinit_service(bastionguard-sanesecurity process false)
bg_install_dinit_service(bastionguard-sanesecurity-timer process on-failure)
bg_install_dinit_service(BastionGuard-usbd process on-failure)
bg_install_dinit_service(clamav-clamonacc process on-failure)
if(ENABLE_BASTIONGUARD_SECURE_CONNECTION)
bg_install_dinit_service(bsc-daemon process on-failure)
endif()
function(bg_install_dinit_user_service service_name restart_policy restart_delay)
set(BG_DINIT_USER_SERVICE_NAME "${service_name}")
set(BG_DINIT_USER_SERVICE_RESTART "${restart_policy}")
set(BG_DINIT_USER_RESTART_DELAY "${restart_delay}")
set(_generated_service
"${CMAKE_CURRENT_BINARY_DIR}/init/dinit/user/${service_name}")
configure_file(
data/init/dinit/bastionguard-dinit-user-service.in
"${_generated_service}"
@ONLY
NEWLINE_STYLE UNIX
)
install(FILES "${_generated_service}"
DESTINATION "${BASTIONGUARD_DINIT_USER_DIR}")
endfunction()
bg_install_dinit_user_service(BastionGuard-useragent true 3)
bg_install_dinit_user_service(BastionGuard-privacyd true 3)
bg_install_dinit_user_service(BastionGuard-ransomware-alert on-failure 3)
bg_install_dinit_user_service(BastionGuard-ransomware-realtime-alert true 3)
bg_install_dinit_user_service(BastionGuard-ransomware-scanner true 3)
bg_install_dinit_user_service(BastionGuard-pacd true 3)
bg_install_dinit_user_service(BastionGuard-mailproxy true 3)
bg_install_dinit_user_service(BastionGuard-user-session-watch true 3)
if(ENABLE_CEF AND ENABLE_CEF_DAEMON)
bg_install_dinit_user_service(BastionGuard-cef true 3)
endif()
install(FILES data/init/common/bastionguard-user-services.desktop
DESTINATION /etc/xdg/autostart)
endif()
# Mantiene la copia dati dell'unità CEF prevista da questo CMake.
if(ENABLE_CEF AND ENABLE_CEF_DAEMON)
install(FILES data/service/BastionGuard-cef.service
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/BastionGuard/data/service
)
@ -2476,6 +2656,7 @@ install(PROGRAMS
data/scripts/BastionGuard-export-env.sh
data/scripts/BastionGuard-locale.sh
data/scripts/BastionGuard-setup-clamav-daemon.sh
data/scripts/BastionGuard-restart-user-services.sh
data/scripts/BastionGuard-user-session-watch.sh
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/BastionGuard/data/scripts
)
@ -2607,40 +2788,38 @@ bg_install_code( "
if(ENABLE_SYSTEMD_SERVICES)
if(ENABLE_INIT_SERVICES)
bg_install_code( "
message(STATUS \"[Systemd] Ricarico configurazione systemd...\")
execute_process(COMMAND systemctl daemon-reload)
if(DEFINED ENV{DESTDIR} AND NOT \"\$ENV{DESTDIR}\" STREQUAL \"\")
message(STATUS \"[Init] DESTDIR attivo: salto enable/start dei servizi\")
else()
message(STATUS \"[Init] Backend: ${BG_INIT_SYSTEM}\")
execute_process(COMMAND ${BG_SERVICECTL_PATH} --system daemon-reload)
message(STATUS \"[Systemd] Abilito BastionGuard-phishing-scanner...\")
execute_process(COMMAND systemctl enable BastionGuard-phishing-scanner.service)
message(STATUS \"[Init] Abilito e avvio BastionGuard-phishing-scanner...\")
execute_process(
COMMAND ${BG_SERVICECTL_PATH} --system enable --now BastionGuard-phishing-scanner.service
)
message(STATUS \"[Systemd] Avvio BastionGuard-phishing-scanner...\")
execute_process(COMMAND systemctl start BastionGuard-phishing-scanner.service)
message(STATUS \"[Init] Abilito e avvio BastionGuard-ransomware-realtime...\")
execute_process(
COMMAND ${BG_SERVICECTL_PATH} --system enable --now BastionGuard-ransomware-realtime.service
)
message(STATUS \"[Systemd] Riavvio BastionGuard-phishing-scanner...\")
execute_process(COMMAND systemctl restart BastionGuard-phishing-scanner.service)
if(${ENABLE_BASTIONGUARD_SECURE_CONNECTION})
message(STATUS \"[Init] Abilito e avvio bsc-daemon...\")
execute_process(
COMMAND ${BG_SERVICECTL_PATH} --system enable --now bsc-daemon.service
)
endif()
message(STATUS \"[Systemd] Abilito BastionGuard-ransomware-realtime...\")
execute_process(COMMAND systemctl enable BastionGuard-ransomware-realtime.service)
message(STATUS \"[Systemd] Avvio BastionGuard-ransomware-realtime...\")
execute_process(COMMAND systemctl start BastionGuard-ransomware-realtime.service)
message(STATUS \"[Systemd] Riavvio BastionGuard-ransomware-realtime...\")
execute_process(COMMAND systemctl restart BastionGuard-ransomware-realtime.service)
message(STATUS \"[Systemd] Abilito BastionGuard-phishing-scanner on graphical...\")
execute_process(COMMAND systemctl enable BastionGuard-restart-on-graphical.service)
message(STATUS \"[Systemd] Riavvio BastionGuard-phishing-scanner on graphical...\")
execute_process(COMMAND systemctl start BastionGuard-restart-on-graphical.service)
message(STATUS \"[Systemd] Riavvio polkit ...\")
execute_process(COMMAND systemctl start polkit.service)
execute_process(
COMMAND ${BG_SERVICECTL_PATH} --system start polkit.service
)
endif()
")
else()
message(STATUS "Systemd service install-time actions are disabled. To enable, run CMake with -DENABLE_SYSTEMD_SERVICES=ON")
message(STATUS "Init service install-time actions are disabled. Use -DENABLE_INIT_SERVICES=ON to enable them")
endif()
# ============================================================

View file

@ -19,8 +19,8 @@
#
Name: bastionguard
Version: 2.0
Release: %mkrel 2
Version: 2.0.1
Release: %mkrel 1
%global yara_version 4.5.5
%global yara_stage %{_builddir}/%{name}-%{version}/.yara-stage
@ -31,8 +31,9 @@ Provides: bastionguard = %{version}-%{release}
Provides: bundled(yara) = %{yara_version}
Obsoletes: bastionguard < %{version}-%{release}
License: GPLv3+ and BSD
URL: https://git.bastionguard.eu/specialworld83/BastionGuard
License: GPLv3
URL: https://bastionguard.eu
Vendor: BastionGuard
Source0: %{name}-%{version}.tar.gz
Source1: https://github.com/VirusTotal/yara/archive/refs/tags/v%{yara_version}.tar.gz#/yara-%{yara_version}.tar.gz

View file

@ -757,8 +757,8 @@ target_include_directories(BastionGuard
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2497,7 +2497,7 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -20,8 +20,8 @@
Name: bastionguard
Version: 2.0
Release: 3
Version: 2.0.1
Release: 1
%global yara_version 4.5.5
%global yara_stage %{_builddir}/%{name}-%{version}/.yara-stage
@ -32,8 +32,10 @@ Provides: bastionguard = %{version}-%{release}
Provides: bundled(yara) = %{yara_version}
Obsoletes: bastionguard < %{version}-%{release}
License: GPLv3+ AND BSD-3-Clause
URL: https://git.bastionguard.eu/specialworld83/BastionGuard
License: GPLv3
URL: https://bastionguard.eu
Vendor: BastionGuard
Source0: %{name}-%{version}.tar.gz
Source1: https://github.com/VirusTotal/yara/archive/refs/tags/v%{yara_version}.tar.gz#/yara-%{yara_version}.tar.gz

View file

@ -763,8 +763,8 @@ target_include_directories(BastionGuard
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2501,7 +2501,7 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -23,11 +23,12 @@
#
Name: bastionguard
Version: 2.0
Version: 2.0.1
Release: 1leap
Summary: BastionGuard Security Platform
License: GPL-3.0-or-later
URL: https://git.bastionguard.eu/specialworld83/BastionGuard
License: GPLv3
URL: https://bastionguard.eu
Vendor: BastionGuard
Source0: %{name}-%{version}.tar.gz
# Disable debuginfo / debugsource packages.

View file

@ -719,8 +719,8 @@ target_include_directories(BastionGuard
)
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2460,7 +2460,7 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -23,11 +23,12 @@
#
Name: bastionguard
Version: 2.0
Release: 2
Version: 2.0.1
Release: 1
Summary: BastionGuard Security Platform
License: GPL-3.0-or-later
URL: https://git.bastionguard.eu/specialworld83/BastionGuard-ci
License: GPLv3
URL: https://bastionguard.eu
Vendor: BastionGuard
Source0: %{name}-%{version}.tar.gz
Provides: bastionguard = %{version}-%{release}

View file

@ -719,8 +719,8 @@ target_include_directories(BastionGuard
)
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2460,7 +2460,7 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -21,7 +21,7 @@
# Maintainer: BastionGuard info@bastionguard.eu
pkgname=bastionguard
pkgver=2.0
pkgver=2.0.1
pkgrel=1
pkgdesc="BastionGuard - transparent security control plane for Linux desktops"
arch=('x86_64')

View file

@ -636,8 +636,8 @@ target_include_directories(BastionGuard
)
target_compile_definitions(BastionGuard PRIVATE
BASTIONGUARD_VERSION="2.0"
BASTIONGUARD_BUILD=20260411
BASTIONGUARD_VERSION="2.0.1"
BASTIONGUARD_BUILD=20260726
)
target_link_libraries(BastionGuard
@ -2384,7 +2384,7 @@ if(BG_INIT_SYSTEM STREQUAL "SYSTEMD")
data/service/bastionguard-sanesecurity.service
data/service/bastionguard-sanesecurity.timer
data/service/BastionGuard-usbd.service
data/service/clamav-clamonacc.service
DESTINATION /usr/lib/systemd/system
)

View file

@ -2740,38 +2740,25 @@ void Backend::sendRansomwareAlert(const std::string& path, const std::string& fa
void Backend::moveToQuarantine(const std::string& path) {
try {
std::string quarantineDir = Backend::getQuarantinePath();
if (!std::filesystem::exists(quarantineDir))
Backend::instance().ensureQuarantinePath();
// Tutte le richieste passano dalla stessa implementazione validata.
// Quarantine::move() accetta esclusivamente file regolari e rifiuta
// directory, symlink e altri oggetti del filesystem.
const bool moved = Quarantine::move(path);
auto src = std::filesystem::path(path);
auto dest = std::filesystem::path(quarantineDir) / src.filename();
std::error_code ec;
std::filesystem::rename(src, dest, ec);
if (ec) {
std::cerr << _("⚠️ Impossibile spostare il file, provo copia: ")
<< ec.message() << "\n";
std::filesystem::copy_file(src, dest,
std::filesystem::copy_options::overwrite_existing, ec);
if (!ec)
std::filesystem::remove(src);
}
std::cout << _("🧰 File spostato in quarantena: ") << dest << "\n";
Glib::signal_idle().connect_once([dest]() {
Glib::signal_idle().connect_once([path, moved]() {
if (moved) {
Utils::show_message(
nullptr,
_("File spostato in quarantena con successo:\n") + dest.string(),
_("File spostato in quarantena con successo:\n") + path,
Gtk::MessageType::INFO);
});
} catch (const std::exception& ex) {
std::cerr << _("❌ Errore durante la quarantena: ") << ex.what() << "\n";
}
} else {
Utils::show_message(
nullptr,
_("Impossibile spostare l'elemento in quarantena. "
"Sono accettati esclusivamente file regolari:\n") + path,
Gtk::MessageType::ERROR);
}
});
}

View file

@ -21,205 +21,396 @@
#include "Resource.hpp"
#include "Quarantine.hpp"
#include "Backend.hpp"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include <system_error>
#include <unistd.h>
#include <glib/gi18n.h>
namespace fs = std::filesystem;
std::string Quarantine::getQuarantinePath() {
namespace {
std::string path = Backend::getQuarantinePath();
if (path.empty()) {
bool is_regular_file_without_following_symlinks(const fs::path& path,
std::error_code& ec)
{
ec.clear();
const fs::file_status status = fs::symlink_status(path, ec);
return !ec && fs::exists(status) && fs::is_regular_file(status);
}
const char* home = std::getenv("HOME");
path = std::string(home ? home : "/tmp") + "/.local/share/BastionGuard/quarantine";
fs::path normalize_path(const fs::path& path, std::error_code& ec)
{
ec.clear();
fs::path normalized = fs::weakly_canonical(path, ec);
if (!ec)
return normalized.lexically_normal();
ec.clear();
normalized = fs::absolute(path, ec);
if (!ec)
return normalized.lexically_normal();
return path.lexically_normal();
}
bool is_path_inside(const fs::path& candidate, const fs::path& directory)
{
std::error_code candidate_ec;
std::error_code directory_ec;
const fs::path normalized_candidate = normalize_path(candidate, candidate_ec);
const fs::path normalized_directory = normalize_path(directory, directory_ec);
if (candidate_ec || directory_ec || normalized_directory.empty())
return false;
auto candidate_it = normalized_candidate.begin();
for (auto directory_it = normalized_directory.begin();
directory_it != normalized_directory.end();
++directory_it, ++candidate_it) {
if (candidate_it == normalized_candidate.end() ||
*candidate_it != *directory_it) {
return false;
}
}
return true;
}
void remove_without_throwing(const fs::path& path)
{
std::error_code ec;
fs::remove(path, ec);
}
bool copy_then_remove(const fs::path& source, const fs::path& destination)
{
std::error_code copy_ec;
fs::copy_file(source, destination, fs::copy_options::none, copy_ec);
if (copy_ec) {
std::cerr << _("❌ Errore copia in quarantena: ")
<< copy_ec.message() << std::endl;
return false;
}
std::error_code remove_ec;
fs::remove(source, remove_ec);
if (remove_ec) {
std::cerr << _("❌ Impossibile rimuovere il file originale dopo la copia: ")
<< remove_ec.message() << std::endl;
// La quarantena non è riuscita: non lasciare una copia che possa
// essere interpretata come isolamento completato.
remove_without_throwing(destination);
return false;
}
return true;
}
} // namespace
std::string Quarantine::getQuarantinePath()
{
std::string path = Backend::getQuarantinePath();
if (path.empty()) {
const char* home = std::getenv("HOME");
path = std::string(home ? home : "/tmp") +
"/.local/share/BastionGuard/quarantine";
}
try {
if (!fs::exists(path)) {
fs::create_directories(path);
const fs::path quarantine_path(path);
if (quarantine_path.empty() ||
quarantine_path == quarantine_path.root_path()) {
std::cerr << _("❌ Percorso di quarantena non valido: ")
<< quarantine_path << std::endl;
return {};
}
std::error_code ec;
fs::create_directories(quarantine_path, ec);
if (ec) {
std::cerr << _("❌ Errore creazione cartella quarantena: ")
<< ec.message() << std::endl;
return {};
}
ec.clear();
if (!fs::is_directory(quarantine_path, ec) || ec) {
std::cerr << _("❌ Il percorso di quarantena non è una directory valida: ")
<< quarantine_path << std::endl;
return {};
}
} catch (const std::exception& e) {
std::cerr << _("❌ Errore creazione cartella quarantena: ") << e.what() << std::endl;
std::cerr << _("❌ Errore creazione cartella quarantena: ")
<< e.what() << std::endl;
return {};
}
return path;
}
bool Quarantine::move(const std::string& filepath) {
bool Quarantine::move(const std::string& filepath)
{
try {
std::string quarantineDir = getQuarantinePath();
std::cerr << "DEBUG move(): quarantineDir=" << quarantineDir << std::endl;
fs::path src(filepath);
if (!fs::exists(src)) {
std::cerr << _("❌ File inesistente: ") << filepath << std::endl;
if (filepath.empty()) {
std::cerr << _("❌ Percorso file vuoto: quarantena annullata")
<< std::endl;
return false;
}
fs::path dest = fs::path(quarantineDir) / src.filename();
std::error_code ec;
fs::path src = fs::absolute(fs::path(filepath), ec);
if (ec) {
std::cerr << _("❌ Impossibile risolvere il percorso del file: ")
<< filepath << " | " << ec.message() << std::endl;
return false;
}
src = src.lexically_normal();
// Protezione fondamentale: non seguire symlink e non accettare
// directory, socket, FIFO o device. Solo file regolari.
if (!is_regular_file_without_following_symlinks(src, ec)) {
std::cerr << _("❌ Quarantena rifiutata: il percorso non è un file regolare: ")
<< src;
if (ec)
std::cerr << " | " << ec.message();
std::cerr << std::endl;
return false;
}
const std::string quarantine_dir_string = getQuarantinePath();
if (quarantine_dir_string.empty())
return false;
const fs::path quarantine_dir(quarantine_dir_string);
// Evita loop e tentativi di mettere nuovamente in quarantena un file
// che si trova già nell'area protetta.
if (is_path_inside(src, quarantine_dir)) {
std::cerr << _("❌ Il file è già contenuto nella quarantena: ")
<< src << std::endl;
return false;
}
fs::path dest = quarantine_dir / src.filename();
int counter = 1;
while (fs::exists(dest) || fs::exists(dest.string() + ".meta")) {
dest = fs::path(quarantineDir) /
(src.stem().string() + "_" + std::to_string(counter) + src.extension().string());
counter++;
dest = quarantine_dir /
(src.stem().string() + "_" + std::to_string(counter) +
src.extension().string());
++counter;
}
std::string metaPath = dest.string() + ".meta";
std::ofstream meta(metaPath);
const fs::path meta_path(dest.string() + ".meta");
std::ofstream meta(meta_path, std::ios::out | std::ios::trunc);
if (!meta.is_open()) {
std::cerr << _("❌ Errore: impossibile creare il file meta in ") << metaPath << std::endl;
std::cerr << _("❌ Impossibile creare i metadata di quarantena: ")
<< meta_path << std::endl;
return false;
}
meta << src.string() << '\n';
meta.flush();
if (!meta.good()) {
meta.close();
remove_without_throwing(meta_path);
std::cerr << _("❌ Scrittura metadata di quarantena fallita: ")
<< meta_path << std::endl;
return false;
}
meta << fs::absolute(src).string();
meta.close();
std::error_code ec;
ec.clear();
fs::rename(src, dest, ec);
if (ec) {
if (ec == std::make_error_code(std::errc::cross_device_link)) {
std::cerr << _("DEBUG move(): filesystem differente, uso copia e rimozione\n");
if (ec == std::errc::cross_device_link) {
std::cerr << _("DEBUG move(): cross-device link, uso copy+remove\n");
std::error_code ec_copy;
fs::copy_file(src, dest, fs::copy_options::overwrite_existing, ec_copy);
if (ec_copy) {
std::cerr << _("❌ Errore copia in quarantena: ")
<< ec_copy.message() << std::endl;
fs::remove(metaPath);
if (!copy_then_remove(src, dest)) {
remove_without_throwing(meta_path);
return false;
}
std::error_code ec_rm;
fs::remove(src, ec_rm);
if (ec_rm) {
std::cerr << _("⚠ Impossibile rimuovere il file originale: ")
<< ec_rm.message() << std::endl;
}
} else {
std::cerr << _("❌ Errore spostamento quarantena: ")
<< ec.message() << std::endl;
fs::remove(metaPath);
remove_without_throwing(meta_path);
return false;
}
}
std::cout << _("✔ File spostato in quarantena: ") << dest << std::endl;
std::cout << _("✔ File spostato in quarantena: ")
<< dest << std::endl;
return true;
} catch (const std::exception& e) {
std::cerr << _("❌ Errore spostamento quarantena: ") << e.what() << std::endl;
std::cerr << _("❌ Errore spostamento quarantena: ")
<< e.what() << std::endl;
return false;
}
}
bool Quarantine::restore(const std::string& quarantinedFile) {
bool Quarantine::restore(const std::string& quarantinedFile)
{
try {
fs::path qf(quarantinedFile);
fs::path meta = qf.string() + ".meta";
std::error_code ec;
fs::path qf = fs::absolute(fs::path(quarantinedFile), ec);
if (ec) {
std::cerr << _("❌ Percorso quarantena non valido: ")
<< quarantinedFile << " | " << ec.message() << std::endl;
return false;
}
qf = qf.lexically_normal();
if (!fs::exists(meta)) {
std::cerr << _("❌ Ripristino impossibile: metadata mancante per ")
<< quarantinedFile << std::endl;
const std::string quarantine_dir_string = getQuarantinePath();
if (quarantine_dir_string.empty())
return false;
const fs::path quarantine_dir(quarantine_dir_string);
if (!is_path_inside(qf, quarantine_dir)) {
std::cerr << _("❌ Ripristino rifiutato: file esterno alla quarantena: ")
<< qf << std::endl;
return false;
}
if (!is_regular_file_without_following_symlinks(qf, ec)) {
std::cerr << _("❌ Ripristino rifiutato: elemento non regolare: ")
<< qf << std::endl;
return false;
}
const fs::path meta(qf.string() + ".meta");
if (!is_regular_file_without_following_symlinks(meta, ec)) {
std::cerr << _("❌ Ripristino impossibile: metadata mancante o non valido per ")
<< qf << std::endl;
return false;
}
std::ifstream in(meta);
std::string originalPath;
std::getline(in, originalPath);
std::string original_path;
std::getline(in, original_path);
in.close();
if (originalPath.empty()) {
if (original_path.empty()) {
std::cerr << _("❌ Ripristino impossibile: metadata vuoto o corrotto in ")
<< meta << std::endl;
return false;
}
fs::path orig = fs::absolute(originalPath);
fs::path original = fs::absolute(fs::path(original_path), ec);
if (ec) {
std::cerr << _("❌ Percorso originale non valido nei metadata: ")
<< original_path << " | " << ec.message() << std::endl;
return false;
}
original = original.lexically_normal();
if (!fs::exists(qf)) {
std::cerr << _("❌ Ripristino impossibile: file in quarantena mancante ")
<< qf << std::endl;
fs::remove(meta);
if (is_path_inside(original, quarantine_dir)) {
std::cerr << _("❌ Ripristino rifiutato: destinazione interna alla quarantena: ")
<< original << std::endl;
return false;
}
fs::create_directories(orig.parent_path());
fs::path finalDest = orig;
int counter = 1;
while (fs::exists(finalDest)) {
finalDest = orig.parent_path() /
(orig.stem().string() + "_restored" +
std::to_string(counter) + orig.extension().string());
counter++;
fs::create_directories(original.parent_path(), ec);
if (ec) {
std::cerr << _("❌ Impossibile ricreare la directory originale: ")
<< original.parent_path() << " | " << ec.message() << std::endl;
return false;
}
std::error_code ec;
fs::rename(qf, finalDest, ec);
fs::path final_dest = original;
int counter = 1;
while (fs::exists(final_dest)) {
final_dest = original.parent_path() /
(original.stem().string() + "_restored" +
std::to_string(counter) + original.extension().string());
++counter;
}
ec.clear();
fs::rename(qf, final_dest, ec);
if (ec) {
if (ec == std::errc::cross_device_link) {
std::cerr << _("DEBUG restore(): cross-device link, uso copy+remove\n");
if (ec == std::make_error_code(std::errc::cross_device_link)) {
std::cerr << _("DEBUG restore(): filesystem differente, uso copia e rimozione\n");
std::error_code ec_copy;
fs::copy_file(qf, finalDest, fs::copy_options::overwrite_existing, ec_copy);
if (ec_copy) {
std::cerr << _("❌ Errore copia durante il ripristino: ")
<< ec_copy.message() << std::endl;
if (!copy_then_remove(qf, final_dest))
return false;
}
std::error_code ec_rm;
fs::remove(qf, ec_rm);
if (ec_rm) {
std::cerr << _("⚠ Impossibile rimuovere il file in quarantena: ")
<< ec_rm.message() << std::endl;
}
} else {
std::cerr << _("❌ Errore ripristino: ") << ec.message() << std::endl;
std::cerr << _("❌ Errore ripristino: ")
<< ec.message() << std::endl;
return false;
}
}
fs::remove(meta);
remove_without_throwing(meta);
std::cout << _("✔ File ripristinato in: ") << finalDest << std::endl;
std::cout << _("✔ File ripristinato in: ")
<< final_dest << std::endl;
return true;
} catch (const std::exception& e) {
std::cerr << _("❌ Errore ripristino: ") << e.what() << std::endl;
std::cerr << _("❌ Errore ripristino: ")
<< e.what() << std::endl;
return false;
}
}
bool Quarantine::remove(const std::string& quarantinedFile) {
bool Quarantine::remove(const std::string& quarantinedFile)
{
try {
fs::path qf(quarantinedFile);
fs::path meta = qf.string() + ".meta";
std::error_code ec;
fs::path qf = fs::absolute(fs::path(quarantinedFile), ec);
if (ec) {
std::cerr << _("❌ Percorso quarantena non valido: ")
<< quarantinedFile << " | " << ec.message() << std::endl;
return false;
}
qf = qf.lexically_normal();
if (fs::exists(qf)) fs::remove(qf);
if (fs::exists(meta)) fs::remove(meta);
const std::string quarantine_dir_string = getQuarantinePath();
if (quarantine_dir_string.empty())
return false;
std::cout << _("✔ File eliminato dalla quarantena: ") << quarantinedFile << std::endl;
if (!is_path_inside(qf, fs::path(quarantine_dir_string))) {
std::cerr << _("❌ Eliminazione rifiutata: file esterno alla quarantena: ")
<< qf << std::endl;
return false;
}
if (!is_regular_file_without_following_symlinks(qf, ec)) {
std::cerr << _("❌ Eliminazione rifiutata: elemento non regolare: ")
<< qf << std::endl;
return false;
}
const fs::path meta(qf.string() + ".meta");
ec.clear();
fs::remove(qf, ec);
if (ec) {
std::cerr << _("❌ Errore eliminazione file in quarantena: ")
<< ec.message() << std::endl;
return false;
}
remove_without_throwing(meta);
std::cout << _("✔ File eliminato dalla quarantena: ")
<< qf << std::endl;
return true;
} catch (const std::exception& e) {
std::cerr << _("❌ Errore eliminazione: ") << e.what() << std::endl;
std::cerr << _("❌ Errore eliminazione: ")
<< e.what() << std::endl;
return false;
}
}

View file

@ -95,10 +95,25 @@ bool QuarantinePage::refreshList() {
std::error_code ec_q;
for (const auto& entry : fs::directory_iterator(quarantineDir, ec_q)) {
if (ec_q) break;
if (!entry.is_regular_file()) continue;
std::error_code ec_type;
const fs::file_status status = entry.symlink_status(ec_type);
if (ec_type || !fs::is_regular_file(status))
continue;
// ignora i metadata
if (entry.path().extension() == ".meta") continue;
// Un file .meta è un sidecar solo quando esiste il payload con lo
// stesso nome senza l'ultima estensione. In questo modo un malware
// reale chiamato, per esempio, sample.meta resta visibile nella GUI.
if (entry.path().extension() == ".meta") {
fs::path payload = entry.path();
payload.replace_extension();
std::error_code ec_payload;
const fs::file_status payload_status =
fs::symlink_status(payload, ec_payload);
if (!ec_payload && fs::is_regular_file(payload_status))
continue;
}
any = true;

1213
src/activation.cpp Normal file

File diff suppressed because it is too large Load diff

36
src/activation.hpp Normal file
View file

@ -0,0 +1,36 @@
/*
* BastionGuard Recovery Data
* Copyright (C) 20252026 Calogero Scarnà. All rights reserved.
*
* Proprietary activation support for donation-based distribution.
*/
#pragma once
#include <string>
namespace BastionGuard::Activation {
struct ActivationStatus {
bool active = false;
bool expired = false;
std::string machine_id;
std::string motherboard_serial;
std::string owner;
std::string edition;
std::string expires;
std::string message;
};
std::string activation_engine_id();
std::string machine_id();
std::string motherboard_serial();
std::string activation_key_path();
std::string hardware_cache_path();
bool refresh_hardware_cache(std::string& error_message);
bool save_system_key_if_valid(const std::string& raw_key, std::string& error_message);
ActivationStatus validate_key(const std::string& raw_key);
ActivationStatus validate_installed_key();
bool save_key_if_valid(const std::string& raw_key, std::string& error_message);
} // namespace BastionGuard::Activation

View file

@ -0,0 +1,66 @@
/*
* BastionGuard Activation Helper
* Runs through pkexec to read root-only DMI identifiers and save the
* donation-bundle activation key system-wide.
*/
#include "activation.hpp"
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <unistd.h>
namespace {
std::string read_stdin_all() {
std::ostringstream content;
content << std::cin.rdbuf();
return content.str();
}
void print_hardware_info() {
std::cout << "MACHINE_ID=" << BastionGuard::Activation::machine_id() << "\n"
<< "MOTHERBOARD_SERIAL=" << BastionGuard::Activation::motherboard_serial() << "\n"
<< "ENGINE=" << BastionGuard::Activation::activation_engine_id() << "\n"
<< "KEY_FORMAT=BGRD3 + KEYID" << "\n"
<< "ACTIVATION_KEY_PATH=" << BastionGuard::Activation::activation_key_path() << "\n"
<< "HARDWARE_CACHE_PATH=" << BastionGuard::Activation::hardware_cache_path() << "\n";
}
} // namespace
int main(int argc, char** argv) {
if (::geteuid() != 0) {
std::cerr << "This helper must run with administrator rights through pkexec.\n";
return 10;
}
const std::string command = (argc >= 2 && argv[1]) ? argv[1] : "";
if (command == "hardware") {
std::string error;
if (!BastionGuard::Activation::refresh_hardware_cache(error)) {
std::cerr << error << "\n";
return 20;
}
print_hardware_info();
return 0;
}
if (command == "save-key") {
const std::string raw_key = read_stdin_all();
std::string error;
if (!BastionGuard::Activation::save_system_key_if_valid(raw_key, error)) {
std::cerr << error << "\n";
return 30;
}
std::cout << "OK\n";
print_hardware_info();
return 0;
}
std::cerr << "Usage: bastionguard-activation-helper hardware | save-key\n";
return 64;
}

View file

@ -301,6 +301,21 @@ private:
continue;
}
// Il percorso ricevuto dal processo realtime deve indicare
// esclusivamente un file regolare assoluto. Non seguire
// symlink e non mostrare azioni di quarantena per directory.
const fs::path alert_path(file);
std::error_code path_ec;
const fs::file_status path_status =
fs::symlink_status(alert_path, path_ec);
if (!alert_path.is_absolute() || path_ec ||
!fs::exists(path_status) ||
!fs::is_regular_file(path_status)) {
log_user(_("[SCARTATO] Percorso alert non regolare: ") + file);
continue;
}
Glib::signal_idle().connect_once([this, file, family]() {
if (!running.load()) {
return;

View file

@ -59,6 +59,98 @@ static const std::string LOG_FILE = "/var/log/BastionGuard/antiransom_inotify.lo
static std::vector<std::string> WATCH_DIRS;
static std::string SECURITY_TOKEN;
static std::vector<std::filesystem::path> EXCLUDED_DIRS;
static inline bool is_regular_file_safe(const std::string& path)
{
std::error_code ec;
const std::filesystem::file_status status =
std::filesystem::symlink_status(path, ec);
return !ec && std::filesystem::exists(status) &&
std::filesystem::is_regular_file(status);
}
static std::filesystem::path normalize_path(const std::filesystem::path& path,
std::error_code& ec)
{
ec.clear();
std::filesystem::path normalized =
std::filesystem::weakly_canonical(path, ec);
if (!ec)
return normalized.lexically_normal();
ec.clear();
normalized = std::filesystem::absolute(path, ec);
if (!ec)
return normalized.lexically_normal();
return path.lexically_normal();
}
static bool is_path_inside(const std::filesystem::path& candidate,
const std::filesystem::path& directory)
{
std::error_code candidate_ec;
std::error_code directory_ec;
const auto normalized_candidate = normalize_path(candidate, candidate_ec);
const auto normalized_directory = normalize_path(directory, directory_ec);
if (candidate_ec || directory_ec || normalized_directory.empty())
return false;
auto candidate_it = normalized_candidate.begin();
for (auto directory_it = normalized_directory.begin();
directory_it != normalized_directory.end();
++directory_it, ++candidate_it) {
if (candidate_it == normalized_candidate.end() ||
*candidate_it != *directory_it) {
return false;
}
}
return true;
}
static bool is_excluded_path(const std::string& path)
{
if (path.empty())
return false;
const std::filesystem::path candidate(path);
for (const auto& excluded : EXCLUDED_DIRS) {
if (is_path_inside(candidate, excluded))
return true;
}
return false;
}
static std::string configured_quarantine_path(const std::string& home)
{
const std::string fallback =
home + "/.local/share/BastionGuard/quarantine";
const std::string config =
home + "/.config/BastionGuard/config.ini";
std::ifstream in(config);
if (!in.is_open())
return fallback;
std::string line;
while (std::getline(in, line)) {
const auto pos = line.find('=');
if (pos == std::string::npos)
continue;
const std::string key = line.substr(0, pos);
const std::string value = line.substr(pos + 1);
if (key == "quarantinePath" && !value.empty())
return value;
}
return fallback;
}
void signal_handler(int sig)
{
@ -489,6 +581,13 @@ static bool load_or_create_token()
static void send_socket_alert(const std::string& file, const std::string& family)
{
// Non inviare alert azionabili per directory, symlink o file già
// contenuti nella quarantena.
if (!is_regular_file_safe(file) || is_excluded_path(file)) {
log_msg(_("Alert non inviato: percorso non regolare o escluso: ") + file);
return;
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return;
@ -577,12 +676,6 @@ static std::string get_process_exe(pid_t pid)
return buf;
}
static inline bool is_regular_file_safe(const std::string& path)
{
std::error_code ec;
return std::filesystem::is_regular_file(path, ec) && !ec;
}
static inline bool looks_like_archive_path(const std::string& path)
{
std::string lower = path;
@ -604,6 +697,11 @@ static void send_archive_alert(
const std::string& file,
const ArchiveInspectionResult& ar)
{
if (!is_regular_file_safe(file) || is_excluded_path(file)) {
log_msg(_("Alert archivio non inviato: percorso non regolare o escluso: ") + file);
return;
}
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
return;
@ -757,6 +855,9 @@ public:
bool scan_file(const std::string& path)
{
if (!is_regular_file_safe(path) || is_excluded_path(path))
return false;
std::lock_guard<std::mutex> lock(yara_mutex);
if (!rules)
@ -967,6 +1068,11 @@ public:
{
std::error_code ec;
if (is_excluded_path(root)) {
log_msg(_("SKIP: directory esclusa dal realtime: ") + root);
return;
}
if (!std::filesystem::exists(root, ec) || ec) {
log_msg("SKIP: " + root + _(" non accessibile"));
return;
@ -987,10 +1093,18 @@ public:
}
const auto& entry = *it;
const std::string entry_path = entry.path().string();
if (is_excluded_path(entry_path)) {
std::error_code type_ec;
if (entry.is_directory(type_ec) && !type_ec)
it.disable_recursion_pending();
continue;
}
ec.clear();
if (entry.is_directory(ec) && !ec) {
add_watch(entry.path().string());
add_watch(entry_path);
}
}
}
@ -1032,6 +1146,12 @@ public:
if (!dir.empty() && ev->len > 0) {
std::string full = dir + "/" + ev->name;
if (is_excluded_path(full)) {
log_msg(_("INOTIFY IGNORATO: percorso escluso: ") + full);
i += sizeof(struct inotify_event) + ev->len;
continue;
}
log_msg("INOTIFY EVENT: " + full + " [" +
decode_mask(ev->mask) + "]");
@ -1116,6 +1236,12 @@ int main(int argc, char* argv[])
std::string home = pw->pw_dir;
EXCLUDED_DIRS.clear();
EXCLUDED_DIRS.emplace_back(configured_quarantine_path(home));
for (const auto& excluded : EXCLUDED_DIRS)
log_msg(_("Directory esclusa dal realtime: ") + excluded.string());
std::error_code ec;
if (!std::filesystem::exists(home, ec) || ec) {
log_msg(_("ERRORE FATALE: HOME non accessibile: ") + home);