45#include <unordered_set>
49#include <glib/gi18n.h>
55#include <nlohmann/json.hpp>
56#include <giomm/dbusconnection.h>
57#include <giomm/dbusinterface.h>
58#include <giomm/dbusownname.h>
59#include <giomm/file.h>
60#include <giomm/fileenumerator.h>
61#include <giomm/fileinfo.h>
62#include <glibmm/i18n.h>
65#include <glibmm/miscutils.h>
66#include <libsmbclient.h>
68namespace fs = std::filesystem;
71#ifdef BASTIONGUARD_VERSION
72 return BASTIONGUARD_VERSION;
79#ifdef BASTIONGUARD_BUILD
80 return BASTIONGUARD_BUILD;
87 return Glib::Base64::encode(s);
91 return Glib::Base64::decode(s);
94static const std::string
SMB_KEY =
"BastionGuard0101SecretKey";
96static std::string
xor_crypt(
const std::string& input) {
97 std::string out = input;
98 for (
size_t i = 0; i < input.size(); ++i)
112static inline std::string
trim(
const std::string& s)
114 size_t start = s.find_first_not_of(
" \t\r\n");
115 if (start == std::string::npos)
return "";
117 size_t end = s.find_last_not_of(
" \t\r\n");
118 return s.substr(start, end - start + 1);
124 auto pos = line.find(
':');
125 if (pos == std::string::npos)
128 return line.substr(0, pos);
134 std::vector<std::string> dirs = {
136 Glib::get_home_dir() +
"/.local/share/clamav",
137 "/usr/local/share/clamav"
151 using namespace std::chrono;
152 auto sctp = time_point_cast<system_clock::duration>(
153 ft - fs::file_time_type::clock::now() + system_clock::now()
155 return system_clock::to_time_t(sctp);
161 std::ifstream f(path, std::ios::binary);
162 if (!f.is_open())
return false;
165 if (!std::getline(f, line))
return false;
168 std::vector<std::string> toks;
170 std::stringstream ss(line);
172 while (std::getline(ss, seg,
':')) {
173 auto l = seg.find_first_not_of(
" \t\r\n");
174 auto r = seg.find_last_not_of(
" \t\r\n");
175 if (l == std::string::npos) toks.push_back(
"");
176 else toks.push_back(seg.substr(l, r - l + 1));
181 for (
int i = 0; i < (int)toks.size(); ++i) {
182 if (toks[i].find(
".cvd") != std::string::npos ||
183 toks[i].find(
".cld") != std::string::npos) {
188 if (nameIdx < 0)
return false;
190 out.
file = fs::path(path).filename().string();
193 for (
int i = nameIdx + 1; i < (int)toks.size(); ++i) {
195 long long v = std::stoll(toks[i]);
196 if (v > 0) { out.
version = v;
break; }
200 for (
int i = nameIdx + 1; i < (int)toks.size(); ++i) {
201 const std::string& t = toks[i];
202 if (std::all_of(t.begin(), t.end(), ::isdigit)) {
203 if (t.size() >= 10 && t.size() <= 13) {
205 long long e = std::stoll(t);
206 if (t.size() > 10) e /= 1000;
207 if (e > 631152000LL && e < 4102444800LL) {
219 auto ft = fs::last_write_time(path);
230 for (
const auto& n : names) {
231 std::string p = dir +
"/" + n;
232 if (fs::exists(p))
return p;
249 const char* home = getenv(
"HOME");
251 return "/tmp/BastionGuard/cred.conf";
253 std::string dir = std::string(home) +
"/.config/BastionGuard";
254 std::filesystem::create_directories(dir);
256 return dir +
"/cred.conf";
262 if (!f.is_open())
return false;
265 while (std::getline(f, line)) {
266 if (line.find(
"enabled=true") != std::string::npos)
275 std::cerr <<
"⚠️ " <<
_(
"Impossibile scrivere la configurazione Samba") <<
"\n";
279 f <<
"enabled=" << (enabled ?
"true" :
"false") <<
"\n";
282 std::cout <<
"ℹ️ " <<
_(
"Stato Samba salvato: ")
283 << (enabled ?
_(
"abilitato") :
_(
"disabilitato")) <<
"\n";
290 constexpr int default_http_port = 81;
291 constexpr int default_https_port = 444;
293 std::ifstream f(
"/etc/BastionGuard/webports.conf");
295 return {default_http_port, default_https_port};
297 int http_port = default_http_port;
298 int https_port = default_https_port;
299 if ((f >> http_port >> https_port) &&
300 http_port > 0 && http_port < 65536 &&
301 https_port > 0 && https_port < 65536) {
302 return {http_port, https_port};
305 return {default_http_port, default_https_port};
309 if ((
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"is-active",
"clamav-daemon.service"}).
exit_code) == 0) {
310 (
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"restart",
"clamav-daemon.service"}).exit_code);
311 std::cout <<
_(
"✔ Riavviato clamav-daemon\n");
312 }
else if ((
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"is-active",
"clamd.service"}).
exit_code) == 0) {
313 (
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"restart",
"clamd.service"}).exit_code);
314 std::cout <<
_(
"✔ Riavviato clamd\n");
316 std::cerr <<
_(
"⚠ Nessun servizio clamd/clamav-daemon trovato\n");
324 const auto installation =
bg_process::run({
"pkexec",
"/usr/bin/install",
"-D",
"-m",
"0644", src, dest});
325 if (!installation.ok()) {
326 std::cerr <<
_(
"⚠ install_to_system_data: pkexec failed (code ")
327 << installation.exit_code <<
")\n";
332 }
catch (
const std::exception& e) {
333 std::cerr <<
_(
"❌ install_to_system_data exception: ") << e.what() <<
"\n";
339static std::string
quarantinePath = Glib::get_home_dir() +
"/.local/share/BastionGuard/quarantine";
342 const char* xdg = std::getenv(
"XDG_CONFIG_HOME");
343 if (xdg && std::strlen(xdg) > 0) {
344 return std::string(xdg);
346 const char* home = std::getenv(
"HOME");
347 if (home)
return std::string(home) +
"/.config";
348 return std::string(
"/tmp");
358 std::filesystem::create_directories(cfgDir);
360 std::string cfgPath = cfgDir +
"/config.ini";
361 std::ofstream f(cfgPath, std::ios::trunc);
363 std::cerr <<
"⚠️ " <<
_(
"Impossibile aprire il file di configurazione per scrittura: ")
364 << cfgPath << std::endl;
368 f <<
"quarantinePath=" << path <<
"\n";
371 std::cout <<
"💾 " <<
_(
"Percorso quarantena salvato in configurazione: ") << path << std::endl;
372 }
catch (
const std::exception& e) {
373 std::cerr <<
"❌ " <<
_(
"Errore durante la scrittura della configurazione: ") << e.what() << std::endl;
380 if (!fs::exists(cfg))
return;
382 std::ifstream f(cfg);
383 if (!f.is_open())
return;
386 while (std::getline(f, line)) {
387 auto pos = line.find(
'=');
388 if (pos == std::string::npos)
continue;
389 std::string key = line.substr(0, pos);
390 std::string val = line.substr(pos + 1);
391 if (key ==
"quarantinePath" && !val.empty()) {
402 }
catch (
const std::exception& e) {
403 std::cerr <<
_(
"❌ Errore creazione cartella quarantena: ") << e.what() << std::endl;
408 "clamav-clamonacc.service",
414 const char* xdg_data = std::getenv(
"XDG_DATA_HOME");
415 if (xdg_data && std::strlen(xdg_data) > 0) {
416 return std::string(xdg_data) +
"/BastionGuard";
419 const char* home = std::getenv(
"HOME");
421 return std::string(home) +
"/.local/share/BastionGuard";
423 return "/tmp/BastionGuard";
433 fs::create_directories(fs::path(dest).parent_path());
434 fs::copy_file(src, dest, fs::copy_options::overwrite_existing);
436 }
catch (
const std::exception& e) {
437 std::cerr <<
_(
"❌ Errore copia ") << src <<
" -> " << dest <<
": " << e.what() << std::endl;
446 "--system",
"is-active", service}).
ok()) {
457 return bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
458 "--system",
"enable",
"--now", service}).ok();
463 return bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
464 "--system",
"disable",
"--now", service}).ok();
469 const auto check =
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
470 "--system",
"is-active", service});
471 if (!check.started)
continue;
472 std::string result = check.
output;
475 result.erase(std::remove(result.begin(), result.end(),
'\n'), result.end());
476 result.erase(std::remove(result.begin(), result.end(),
'\r'), result.end());
478 if (result ==
"active")
506 std::vector<std::string> lines;
508 const auto logs =
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
509 "--system",
"logs", service,
"100"});
510 if (!logs.started)
continue;
511 std::istringstream stream(logs.output);
513 while (std::getline(stream, line)) lines.push_back(line +
"\n");
515 if (!lines.empty())
break;
523 namespace fs = std::filesystem;
524 std::vector<std::string> db_files = {
525 "/var/lib/clamav/daily.cvd",
526 "/var/lib/clamav/main.cvd",
527 "/var/lib/clamav/bytecode.cvd",
528 "/var/lib/clamav/daily.cld",
529 "/var/lib/clamav/main.cld",
530 "/var/lib/clamav/bytecode.cld"
533 std::time_t newest = 0;
534 for (
const auto& file : db_files) {
535 if (fs::exists(file)) {
536 auto ftime = fs::last_write_time(file);
537 auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(
538 ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
539 std::time_t t = std::chrono::system_clock::to_time_t(sctp);
540 if (t > newest) newest = t;
545 return _(
"sconosciuta");
549 localtime_r(&newest, &tmbuf);
550 std::strftime(buf,
sizeof(buf),
"%d %B %Y %H:%M", &tmbuf);
557 namespace fs = std::filesystem;
560 std::vector<std::string> db_files = {
561 "/var/lib/clamav/daily.cld",
562 "/var/lib/clamav/daily.cvd",
563 "/var/lib/clamav/main.cld",
564 "/var/lib/clamav/main.cvd"
567 for (
const auto &file : db_files) {
568 if (!fs::exists(file))
571 std::ifstream f(file, std::ios::binary);
576 std::getline(f, line);
579 size_t first_colon = line.find(
':');
580 size_t second_colon = line.find(
':', first_colon + 1);
581 size_t third_colon = line.find(
':', second_colon + 1);
583 if (first_colon == std::string::npos || second_colon == std::string::npos)
586 std::string date_part = line.substr(first_colon + 1, second_colon - first_colon - 1);
587 std::string version = line.substr(second_colon + 1, third_colon - second_colon - 1);
589 std::ostringstream out;
590 out <<
"daily.cvd v" << version <<
" (" << date_part <<
")";
594 return _(
"sconosciuta");
604 std::vector<std::string> paths;
605 std::ifstream f(
"/etc/clamav/clamd.conf");
606 if (!f.is_open())
return paths;
609 while (std::getline(f, line)) {
610 if (line.find(
"OnAccessIncludePath") == 0) {
611 auto pos = line.find(
' ');
612 if (pos != std::string::npos) {
613 paths.push_back(line.substr(pos + 1));
621 std::vector<std::string> events;
623 const auto logs =
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
624 "--system",
"logs", service,
"50"});
625 if (!logs.started)
continue;
626 std::istringstream stream(logs.output);
628 while (std::getline(stream, line)) {
629 if (line.find(
"Scanned file") != std::string::npos ||
630 line.find(
"FOUND") != std::string::npos ||
631 line.find(
"Access denied") != std::string::npos ||
632 line.find(
"ERROR") != std::string::npos) {
633 events.push_back(line);
637 if (!events.empty())
break;
647 if (args.empty())
return 127;
648 std::vector<std::string> argv = {
"pkexec"};
649 argv.insert(argv.end(), args.begin(), args.end());
655 return id.empty() ?
"unknown" : id;
660 (std::filesystem::exists(
"/usr/sbin/clamd") ||
661 std::filesystem::exists(
"/usr/bin/clamd"));
666 std::cout <<
_(
"✔ clamd già installato\n");
671 std::cout <<
_(
"⚠ clamd non trovato, tentativo installazione per ") << distro <<
"...\n";
674 if (distro ==
"debian" || distro ==
"ubuntu" || distro ==
"linuxmint") {
676 if (ret == 0) ret =
installPackages({
"apt-get",
"install",
"-y",
"clamav",
"clamav-daemon"});
677 }
else if (distro ==
"fedora") {
678 ret =
installPackages({
"dnf",
"install",
"-y",
"clamav",
"clamav-update"});
679 }
else if (distro ==
"centos" || distro ==
"rhel") {
680 ret =
installPackages({
"yum",
"install",
"-y",
"clamav",
"clamav-update"});
681 }
else if (distro ==
"opensuse" || distro ==
"suse") {
683 }
else if (distro ==
"arch" || distro ==
"manjaro" || distro ==
"endeavouros") {
684 ret =
installPackages({
"pacman",
"-S",
"--needed",
"--noconfirm",
"clamav"});
685 }
else if (distro ==
"gentoo" || distro ==
"funtoo") {
687 }
else if (distro ==
"slackware") {
690 std::cerr <<
_(
"❌ Distribuzione non riconosciuta: ") << distro <<
"\n";
695 std::cout <<
_(
"✔ clamd installato correttamente\n");
698 std::cerr <<
_(
"❌ Errore durante l’installazione di clamd\n");
719 Glib::get_home_dir() +
"/.config/BastionGuard/firewall.conf";
721 if (std::filesystem::exists(fwCfg)) {
722 std::ifstream fin(fwCfg);
724 std::getline(fin, line);
726 if (line.find(
"firewalld") != std::string::npos)
728 else if (line.find(
"ufw") != std::string::npos)
733 std::cout <<
"[Backend] Firewall caricato da config: "
734 << line << std::endl;
736 std::cout <<
"[Backend] Firewall autodetect: "
740 std::cerr <<
_(
"[Backend] ⚠ Errore lettura configurazione firewall\n");
746 std::cout <<
_(
"[Backend] 🛰️ Listener D-Bus ransomware attivo\n");
747 }
catch (
const std::exception& e) {
748 std::cerr <<
_(
"[Backend] ⚠ Impossibile avviare listener D-Bus ransomware: ")
749 << e.what() << std::endl;
758 const char* home = getenv(
"HOME");
759 std::string cfgPath = std::string(home) +
"/.config/BastionGuard/googlesafe.conf";
760 if (std::filesystem::exists(cfgPath)) {
761 std::ifstream fin(cfgPath);
763 while (std::getline(fin, line)) {
764 if (line.find(
"google_safe_enabled=true") != std::string::npos)
766 if (line.find(
"google_safe_key=") != std::string::npos) {
767 auto pos = line.find(
'=');
768 if (pos != std::string::npos)
772 std::cout <<
_(
"[Backend] Configurazione Google Safe caricata da ") << cfgPath <<
"\n";
775 std::cerr <<
_(
"[Backend] ⚠ Impossibile leggere config Google Safe\n");
779 std::cout << Glib::ustring::compose(
780 _(
"[Backend] Google Safe Browsing attivo (API Key: %1)\n"),
785 std::cout <<
_(
"[Backend] Google Safe Browsing disattivato.\n");
788 std::string blacklist =
resource(
"phishing/blacklist.txt");
790 if (!std::filesystem::exists(blacklist)) {
791 std::cerr <<
_(
"[Backend] Blacklist non trovata in ") << blacklist
792 <<
_(
" — provo a scaricarla con updatePhishLists()\n");
794 blacklist =
resource(
"phishing/blacklist.txt");
795 std::cout <<
_(
"[Backend] Blacklist aggiornata e trovata in ") << blacklist << std::endl;
797 std::cerr <<
_(
"[Backend] updatePhishLists() fallita, continuerò senza WebProbe\n");
802 (void)warning_https_port;
804 if (!blacklist.empty() && std::filesystem::exists(blacklist)) {
806 webprobe_ = std::make_unique<WebProbe>(blacklist, warning_port);
807 std::cout <<
_(
"[Backend] WebProbe avviato su porta ") << warning_port
808 <<
_(
" con blacklist: ") << blacklist << std::endl;
809 }
catch (
const std::exception& ex) {
810 std::cerr <<
_(
"[Backend] Errore inizializzazione WebProbe: ") << ex.what() << std::endl;
814 std::cerr <<
_(
"[Backend] Nessuna blacklist disponibile, WebProbe non inizializzato\n");
820 std::cout <<
_(
"[Backend] Whitelist caricata con ")
822 }
catch (
const std::exception& e) {
823 std::cerr <<
_(
"[Backend] ⚠ Errore caricamento whitelist: ")
824 << e.what() << std::endl;
838 const int ret =
bg_process::run({
"runuser",
"-u", Glib::get_user_name(),
"--",
839 "/usr/libexec/bastionguard/bastionguard-service",
840 "--user",
"start",
"BastionGuard-ransomware-scanner.service"}).exit_code;
842 std::cout <<
_(
"✔ Servizio Anti-Ransomware avviato\n");
844 std::cerr <<
_(
"❌ Errore avvio servizio Anti-Ransomware\n");
848 const int ret =
bg_process::run({
"runuser",
"-u", Glib::get_user_name(),
"--",
849 "/usr/libexec/bastionguard/bastionguard-service",
850 "--user",
"stop",
"BastionGuard-ransomware-scanner.service"}).exit_code;
852 std::cout <<
_(
"✔ Servizio Anti-Ransomware fermato\n");
854 std::cerr <<
_(
"⚠ Impossibile fermare il servizio Anti-Ransomware\n");
859 namespace fs = std::filesystem;
862 std::string systemYaraDir =
"/usr/share/BastionGuard/data/yara";
864 fs::create_directories(userYaraDir);
866 std::vector<std::string> files = {
867 "ByteCode.MSIL.Ransomware.Apis.yara",
868 "ByteCode.MSIL.Ransomware.Thanos.yara",
869 "Linux.Ransomware.KillDisk.yara",
870 "Win32.Ransomware.WannaCry.yara",
871 "Win32.Ransomware.LockBit.yara",
872 "Win64.Ransomware.BlackBasta.yara",
873 "ByteCode.MSIL.Ransomware.ChupaCabra.yara",
874 "ByteCode.MSIL.Ransomware.Cring.yara",
875 "ByteCode.MSIL.Ransomware.Dusk.yara",
876 "ByteCode.MSIL.Ransomware.EAF.yara",
877 "ByteCode.MSIL.Ransomware.Eternity.yara",
878 "ByteCode.MSIL.Ransomware.Fantom.yara",
879 "ByteCode.MSIL.Ransomware.GhosTEncryptor.yara",
880 "ByteCode.MSIL.Ransomware.Ghostbin.yara",
881 "ByteCode.MSIL.Ransomware.GoodWill.yara",
882 "ByteCode.MSIL.Ransomware.HarpoonLocker.yara",
883 "ByteCode.MSIL.Ransomware.Hog.yara",
884 "ByteCode.MSIL.Ransomware.Invert.yara",
885 "ByteCode.MSIL.Ransomware.Janelle.yara",
886 "ByteCode.MSIL.Ransomware.Khonsari.yara",
887 "ByteCode.MSIL.Ransomware.McBurglar.yara",
888 "ByteCode.MSIL.Ransomware.Moisha.yara",
889 "ByteCode.MSIL.Ransomware.Namaste.yara",
890 "ByteCode.MSIL.Ransomware.Oct.yara",
891 "ByteCode.MSIL.Ransomware.Pacman.yara",
892 "ByteCode.MSIL.Ransomware.PoliceRecords.yara",
893 "ByteCode.MSIL.Ransomware.Povlsomware.yara",
894 "ByteCode.MSIL.Ransomware.Retis.yara",
895 "ByteCode.MSIL.Ransomware.TaRRaK.yara",
896 "ByteCode.MSIL.Ransomware.TimeCrypt.yara",
897 "ByteCode.MSIL.Ransomware.TimeTime.yara",
898 "ByteCode.MSIL.Ransomware.Venom.yara",
899 "ByteCode.MSIL.Ransomware.WildFire.yara",
900 "ByteCode.MSIL.Ransomware.WormLocker.yara",
901 "ByteCode.MSIL.Ransomware.ZeroLocker.yara",
902 "Bytecode.MSIL.Ransomware.CobraLocker.yara",
903 "Linux.Ransomware.GwisinLocker.yara",
904 "Linux.Ransomware.Helldown.yara",
905 "Linux.Ransomware.LuckyJoe.yara",
906 "Linux.Ransomware.RedAlert.yara",
907 "Win32.Ransomware.Conti.yara",
908 "Win32.Ransomware.BlackCat.yara",
909 "Win32.Ransomware.Clop.yara",
910 "Win32.Ransomware.Ryuk.yara",
911 "Win64.Ransomware.Cactus.yara",
912 "Win64.Ransomware.Pandora.yara",
913 "Win64.Ransomware.HermeticRansom.yara"
916 std::string baseUrl =
917 "https://raw.githubusercontent.com/reversinglabs/reversinglabs-yara-rules/develop/yara/ransomware";
919 int total = files.size();
921 int successCount = 0;
923 bool blockedDetected =
false;
925 std::cout <<
_(
"⬇ Inizio aggiornamento delle regole YARA...") <<
"\n";
927 for (
const auto& file : files) {
930 if (progressCallback)
931 progressCallback(index, total, file);
933 std::string url = baseUrl +
"/" + file;
934 std::string dest = userYaraDir +
"/" + file;
936 const auto download =
bg_process::run({
"curl",
"--fail",
"--silent",
"--show-error",
937 "--location",
"--max-time",
"10",
"-o", dest,
"--", url},
true);
938 const std::string& output = download.
output;
939 if (!download.ok()) {
941 fs::remove(dest, ec);
946 if (fs::exists(dest)) {
947 auto size = fs::file_size(dest);
950 output.find(
"redirect_to_local_warning_server") != std::string::npos) {
951 blockedDetected =
true;
957 std::cout <<
_(
"✔ Aggiornato: ") << file <<
"\n";
965 std::cout <<
"\n📊 " <<
_(
"Totale riusciti: ") << successCount
966 <<
" | " <<
_(
"Falliti: ") << failCount <<
"\n";
968 if (blockedDetected) {
969 std::cerr <<
_(
"⚠ Alcuni download sono stati bloccati dall'AntiPhishing.") <<
"\n";
972 std::cout <<
_(
"📁 Regole salvate in: ") << userYaraDir <<
"\n";
975 if (successCount > 0) {
979 bool copied_all =
true;
980 for (
const auto& file : files) {
981 const fs::path src_path = fs::path(userYaraDir) / file;
982 if (!fs::exists(src_path))
continue;
983 const fs::path dst_path = fs::path(systemYaraDir) / file;
984 if (!
bg_process::run({
"pkexec",
"/usr/bin/install",
"-D",
"-m",
"0644",
985 src_path.string(), dst_path.string()}).
ok())
989 std::cout <<
_(
"✔ Copiate anche in /usr/share/BastionGuard/data/yara") <<
"\n";
991 std::cerr <<
_(
"⚠ Alcune regole YARA non sono state installate nel sistema") <<
"\n";
994 return successCount > 0;
1006 const std::string helper =
1007 "/usr/share/BastionGuard/data/scripts/BastionGuard-phishing-updater.sh";
1009 if (!std::filesystem::exists(helper)) {
1010 std::cerr <<
_(
"[Phishing] Helper non trovato: ") << helper <<
"\n";
1017 const pid_t pid = ::fork();
1019 std::cerr <<
_(
"[Phishing] fork() fallita per helper privilegiato.\n");
1024 const char* argv[] = {
1025 "pkexec", helper.c_str(), staging_dir.c_str(),
nullptr
1027 ::execvp(
"pkexec",
const_cast<char* const*
>(argv));
1032 if (::waitpid(pid, &status, 0) < 0)
return false;
1033 return WIFEXITED(status) && WEXITSTATUS(status) == 0;
1043 const std::string txtPath =
1044 Glib::get_home_dir() +
1045 "/.local/share/BastionGuard/phishing/whitelist.txt";
1047 if (!std::filesystem::exists(txtPath))
return;
1049 std::ifstream f(txtPath);
1050 if (!f.is_open())
return;
1052 bool changed =
false;
1054 while (std::getline(f, line)) {
1056 const char* ws =
" \t\r\n\f\v";
1057 size_t s = line.find_first_not_of(ws);
1058 if (s == std::string::npos)
continue;
1059 size_t e = line.find_last_not_of(ws);
1060 line = line.substr(s, e - s + 1);
1061 if (line.empty() || line[0] ==
'#')
continue;
1076 std::ofstream out(txtPath, std::ios::trunc);
1081 std::cout <<
_(
"[Backend] ✅ Whitelist merged: ")
1090 namespace fs = std::filesystem;
1093 std::string baseDir = userBase +
"/data/phishing";
1094 std::string finalPath = baseDir +
"/blacklist.txt";
1095 std::string finalReduce = baseDir +
"/blacklist-reduce.txt";
1099 std::string stage_template =
"/tmp/bastionguard-phish.XXXXXX";
1100 std::vector<char> stage_buf(stage_template.begin(), stage_template.end());
1101 stage_buf.push_back(
'\0');
1102 char* stage_ptr = ::mkdtemp(stage_buf.data());
1104 std::cerr <<
_(
"[Phishing] Impossibile creare staging directory sicura.\n");
1107 std::string stagingDir(stage_ptr);
1108 ::chmod(stagingDir.c_str(), 0700);
1110 std::string tmpPath = stagingDir +
"/blacklist.txt";
1111 std::string tmpReduce = stagingDir +
"/blacklist-reduce.txt";
1112 std::string tmpDnsmasq = stagingDir +
"/dnsmasq-blacklist.conf";
1114 fs::create_directories(baseDir);
1117 std::vector<std::string> paths;
1119 for (
auto &p : paths) {
1121 if (!p.empty() && std::filesystem::exists(p))
1122 std::filesystem::remove(p);
1128 cleanup.paths.push_back(tmpPath);
1129 cleanup.paths.push_back(tmpReduce);
1130 cleanup.paths.push_back(tmpDnsmasq);
1131 cleanup.paths.push_back(stagingDir);
1133 std::vector<std::string> sources = {
1134 "https://phishing.army/download/phishing_army_blocklist.txt",
1135 "https://openphish.com/feed.txt",
1136 "https://urlhaus.abuse.ch/downloads/text/",
1139 auto trim = [](std::string &s) {
1140 const char *ws =
" \t\n\r\f\v";
1141 size_t start = s.find_first_not_of(ws);
1142 if (start == std::string::npos) { s.clear();
return; }
1143 size_t end = s.find_last_not_of(ws);
1144 s = s.substr(start, end - start + 1);
1147 const std::regex re_ipv4(R
"((?:(?:25[0-5]|2[0-4]\d|1?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|1?\d{1,2})){3}))");
1148 const std::regex re_ipv6(R
"((?:[0-9a-fA-F]{1,4}(?::[0-9a-fA-F]{1,4}){2,7}))");
1150 auto looks_like_ip = [&](
const std::string &s)->
bool{
1151 return std::regex_search(s, re_ipv4) || std::regex_search(s, re_ipv6);
1154 auto looks_like_url_or_domain = [](
const std::string &s) ->
bool {
1155 if (s.empty())
return false;
1156 if (s.find(
"http://") != std::string::npos || s.find(
"https://") != std::string::npos)
return true;
1157 if (s.find(
'.') != std::string::npos) {
1158 bool all_digits =
true;
1160 if (!std::isdigit(
static_cast<unsigned char>(c)) && c !=
'.') { all_digits =
false;
break; }
1169 std::ofstream out(tmpPath, std::ios::trunc);
1170 if (!out.is_open()) {
1171 std::cerr <<
_(
"❌ Impossibile scrivere ") << tmpPath <<
"\n";
1175 for (
const auto& url : sources) {
1176 const auto download =
bg_process::run({
"curl",
"--fail",
"--silent",
"--max-time",
"30",
1177 "--user-agent",
"BastionGuard-PhishUpdater/1.0",
1178 "--", url},
false, 16U * 1024U * 1024U);
1179 if (!download.ok()) { std::cerr <<
_(
"⚠ Impossibile aprire ") << url <<
"\n";
continue; }
1183 std::istringstream fetched(download.output);
1184 std::string fragment;
1185 while (std::getline(fetched, fragment)) {
1186 acc.append(fragment).append(
"\n");
1188 size_t nl = acc.find(
'\n');
1189 if (nl == std::string::npos)
break;
1190 std::string line = acc.substr(0, nl);
1191 acc.erase(0, nl + 1);
1192 if (!line.empty() && line.back() ==
'\r') line.pop_back();
1194 if (line.empty() || line[0] ==
'#')
continue;
1196 if (looks_like_ip(line) || looks_like_url_or_domain(line)) {
1197 out << line <<
"\n";
1202 if (!any) std::cerr <<
_(
"⚠ Nessun dato da ") << url <<
"\n";
1206 ::chmod(tmpPath.c_str(), 0600);
1211 std::ifstream fin(tmpPath);
1212 if (!fin.is_open())
return false;
1214 std::unordered_set<std::string> seen;
1215 std::vector<std::string> lines;
1217 while (std::getline(fin, line)) {
1218 if (!line.empty() && line.back() ==
'\r') line.pop_back();
1220 if (line.empty() || line[0] ==
'#')
continue;
1221 if (seen.insert(line).second) lines.push_back(line);
1225 const size_t maxLines = 30;
1226 std::ofstream fout(tmpReduce, std::ios::trunc);
1227 for (
size_t i = 0; i < std::min(lines.size(), maxLines); ++i)
1228 fout << lines[i] <<
"\n";
1229 fout <<
_(
"# ... lista completa salvata in blacklist.txt\n");
1231 ::chmod(tmpReduce.c_str(), 0600);
1238 std::ifstream fin(finalPath);
1239 if (!fin.is_open()) {
1240 std::cerr <<
_(
"❌ Impossibile aprire la blacklist per generare dnsmasq.") << std::endl;
1242 std::ofstream fout(tmpDnsmasq, std::ios::trunc);
1243 if (!fout.is_open()) {
1244 std::cerr <<
_(
"❌ Impossibile creare file temporaneo dnsmasq.") << std::endl;
1248 static const std::unordered_set<std::string> infra_whitelist = {
1250 "githubusercontent.com",
1267 "azurewebsites.net",
1275 "googleusercontent.com",
1278 "firebasestorage.googleapis.com",
1286 std::unordered_set<std::string> trusted;
1288 auto load_json_list = [&](
const std::string& path) {
1289 if (!fs::exists(path))
return;
1291 std::ifstream f(path);
1295 auto push_str = [&](
const nlohmann::json& arr) {
1296 for (
auto& v : arr) {
1297 if (v.is_string()) trusted.insert(v.get<std::string>());
1303 }
else if (j.contains(
"list") && j[
"list"].is_array()) {
1304 push_str(j[
"list"]);
1305 }
else if (j.contains(
"whitelist") && j[
"whitelist"].is_array()) {
1306 push_str(j[
"whitelist"]);
1311 auto load_text_list = [&](
const std::string& path) {
1312 if (!fs::exists(path))
return;
1315 std::ifstream f(path);
1317 while (std::getline(f, line)) {
1318 line.erase(std::remove(line.begin(), line.end(),
'\r'), line.end());
1319 line.erase(std::remove(line.begin(), line.end(),
'\n'), line.end());
1321 const char* ws =
" \t\f\v";
1322 size_t start = line.find_first_not_of(ws);
1323 if (start == std::string::npos)
continue;
1324 size_t end = line.find_last_not_of(ws);
1325 line = line.substr(start, end - start + 1);
1327 if (line.empty() || line[0] ==
'#')
1330 trusted.insert(line);
1335 load_json_list(
"/usr/share/BastionGuard/data/bank/banks.json");
1337 if (
const char* home = std::getenv(
"HOME")) {
1338 load_json_list(std::string(home) +
"/.config/BastionGuard/whitelist.json");
1339 load_text_list(std::string(home) +
"/.local/share/BastionGuard/phishing/whitelist.txt");
1342 auto clean_domain = [](std::string s) {
1343 std::transform(s.begin(), s.end(), s.begin(),
1344 [](
unsigned char c){ return (char)std::tolower(c); });
1346 const char* ws =
" \t\r\n\f\v";
1347 size_t start = s.find_first_not_of(ws);
1348 if (start == std::string::npos)
return std::string{};
1349 size_t end = s.find_last_not_of(ws);
1350 s = s.substr(start, end - start + 1);
1352 if (
auto pos = s.find(
"://"); pos != std::string::npos)
1353 s = s.substr(pos + 3);
1355 for (
char c : {
'/',
' ',
';',
'"',
'\'',
'%',
'&',
'(',
')',
'=',
'?',
'*',
'#'})
1356 if (
auto p = s.find(c); p != std::string::npos)
1359 if (
auto at = s.rfind(
'@'); at != std::string::npos)
1360 s = s.substr(at + 1);
1362 if (
auto colon = s.find(
':'); colon != std::string::npos)
1363 s = s.substr(0, colon);
1365 if (s.rfind(
"www.", 0) == 0)
1368 while (!s.empty() && s.front() ==
'.')
1370 while (!s.empty() && s.back() ==
'.')
1377 auto is_whitelisted_domain = [&](
const std::string& domain,
1378 const std::unordered_set<std::string>& wl) ->
bool {
1379 if (domain.empty())
return false;
1380 if (wl.count(domain))
return true;
1382 size_t dot = domain.find(
'.');
1383 while (dot != std::string::npos) {
1384 std::string parent = domain.substr(dot + 1);
1385 if (wl.count(parent))
return true;
1386 dot = domain.find(
'.', dot + 1);
1392 if (!trusted.empty()) {
1393 std::unordered_set<std::string> normalized;
1394 normalized.reserve(trusted.size());
1395 for (
const auto& d : trusted) normalized.insert(clean_domain(d));
1396 trusted.swap(normalized);
1399 std::cerr <<
_(
"[Backend] ✅ Whitelist utente/banca caricata: ")
1400 << trusted.size() <<
" domini.\n";
1401 std::cerr <<
_(
"[Backend] ✅ Whitelist infrastrutturale: ")
1402 << infra_whitelist.size() <<
_(
" domini.\n");
1404 size_t written = 0, skipped = 0, skipped_ip = 0;
1407 while (std::getline(fin, line)) {
1408 line.erase(std::remove(line.begin(), line.end(),
'\r'), line.end());
1409 line.erase(std::remove(line.begin(), line.end(),
'\n'), line.end());
1410 if (line.empty() || line[0] ==
'#')
continue;
1413 std::string host = line;
1415 if (
auto pos = host.find(
"://"); pos != std::string::npos)
1416 host = host.substr(pos + 3);
1419 for (
char c : {
'/',
' ',
';',
'"',
'\'',
'%',
'&',
'(',
')',
'=',
'?',
'*',
'#'})
1420 if (
auto p = host.find(c); p != std::string::npos)
1421 host = host.substr(0, p);
1424 if (
auto at = host.rfind(
'@'); at != std::string::npos)
1425 host = host.substr(at + 1);
1428 if (
auto colon = host.find(
':'); colon != std::string::npos)
1429 host = host.substr(0, colon);
1431 std::string clean_host = clean_domain(host);
1432 if (clean_host.empty())
continue;
1434 if (looks_like_ip(clean_host)) {
1440 if (is_whitelisted_domain(clean_host, infra_whitelist)) {
1444 if (is_whitelisted_domain(clean_host, trusted)) {
1449 fout <<
"address=/" << clean_host <<
"/127.0.0.2\n";
1452 if (written % 1000 == 0) fout.flush();
1453 if (written > 1000000)
break;
1457 ::chmod(tmpDnsmasq.c_str(), 0600);
1460 std::cout <<
_(
"✔ File dnsmasq generato: ") << written
1461 <<
_(
" voci. Skipped whitelist: ") << skipped
1462 <<
_(
" | Skipped IP: ") << skipped_ip <<
"\n";
1466 std::cerr <<
_(
"[Phishing] Installazione privilegiata annullata o fallita; ")
1467 <<
_(
"nessun fallback insicuro viene eseguito.\n");
1470 fs::remove(tmpDnsmasq);
1473 }
catch (
const std::exception& e) {
1474 std::cerr <<
_(
"⚠ Errore generazione dnsmasq blocklist: ") << e.what() << std::endl;
1482 std::cout <<
_(
"[Firewall] Blocco IP disabilitato — salto applicazione regole.\n");
1484 std::cout <<
_(
"[Firewall] Nessun firewall supportato rilevato.\n");
1486 std::ifstream fin(finalPath);
1487 std::vector<std::string> lines;
1490 while (std::getline(fin, line))
1491 lines.push_back(line);
1493 const auto before = lines.size();
1497 std::cout <<
_(
"[Firewall] Tentata applicazione regole da ")
1498 << before <<
_(
" righe blacklist ")
1499 <<
"(firewall=" <<
static_cast<int>(
firewallType_) <<
")\n";
1502 catch (
const std::exception& e) {
1503 std::cerr <<
_(
"[Firewall] Errore applicazione regole firewall: ")
1504 << e.what() << std::endl;
1507 std::cerr <<
_(
"[Firewall] Errore sconosciuto applicazione regole firewall.\n");
1511 std::cout <<
_(
"✔ Blacklist phishing aggiornata in ") << finalPath
1512 <<
_(
" e ridotta in ") << finalReduce <<
"\n";
1521 std::cout <<
_(
"▶ Avvio protezione Anti-Phishing...\n");
1522 int ret = (
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"start",
"BastionGuard-phishing-scanner.service"}).exit_code);
1524 std::cout <<
_(
"✔ Servizio Anti-Phishing avviato\n");
1526 std::cerr <<
_(
"❌ Errore avvio servizio Anti-Phishing\n");
1531 std::cout <<
_(
"⏹ Arresto protezione Anti-Phishing...\n");
1532 int ret = (
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"stop",
"BastionGuard-phishing-scanner.service"}).exit_code);
1534 std::cout <<
_(
"✔ Servizio Anti-Phishing fermato\n");
1536 std::cerr <<
_(
"⚠ Errore arresto BastionGuard-phishing-scanner.service\n");
1544 namespace fs = std::filesystem;
1547 std::string baseDir = userBase +
"/data/sanesecurity";
1548 std::string tmpDir =
"/tmp/sanesecurity";
1550 fs::create_directories(tmpDir);
1551 fs::create_directories(baseDir);
1553 std::vector<std::string> dbs = {
1561 int total =
static_cast<int>(dbs.size());
1564 std::cout <<
_(
"⬇ Inizio aggiornamento Sanesecurity DB...") <<
"\n";
1566 for (
const auto& db : dbs) {
1568 if (progressCallback)
1569 progressCallback(current - 1, total, db);
1571 std::string url =
"https://sanesecurity.com/clamav/" + db;
1572 std::string dest = tmpDir +
"/" + db;
1573 std::string finalPath = baseDir +
"/" + db;
1574 std::string systemDest =
"/usr/share/BastionGuard/data/sanesecurity/" + db;
1576 std::cout <<
_(
"⬇ Scarico ") << db <<
" ...\n";
1578 const auto download =
bg_process::run({
"curl",
"--fail",
"--silent",
"--location",
1579 "--max-time",
"30",
"-o", dest,
"--", url});
1582 if (ret != 0 || !fs::exists(dest) || fs::file_size(dest) < 100) {
1583 std::cerr <<
_(
"⚠ Errore download o file vuoto: ") << db <<
"\n";
1584 if (progressCallback)
1585 progressCallback(current, total, db);
1591 std::cerr <<
_(
"❌ Errore copia locale ") << finalPath <<
"\n";
1597 std::cout <<
_(
"✔ ") << db <<
_(
" installato system-wide in ") << systemDest <<
"\n";
1599 std::cout <<
_(
"ℹ ") << db <<
_(
" disponibile solo in ") << finalPath <<
"\n";
1602 if (progressCallback)
1603 progressCallback(current, total, db);
1606 std::cout <<
_(
"✔ Database Sanesecurity aggiornato in ") << baseDir <<
"\n";
1614 return bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
1615 "--user",
"is-active",
"BastionGuard-ransomware-scanner.service"}).ok();
1619 int ret = (
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"is-active",
"BastionGuard-phishing-scanner.service"}).exit_code);
1631 std::string result =
webprobe_->check_url(url);
1633 if (result != url) {
1650 const char* home = getenv(
"HOME");
1652 std::cerr <<
"[Backend] ❌ " <<
_(
"Variabile HOME non trovata") <<
"\n";
1656 std::string cfgDir = std::string(home) +
"/.config/BastionGuard";
1657 std::string cfgPath = cfgDir +
"/googlesafe.conf";
1659 std::filesystem::create_directories(cfgDir);
1661 std::ofstream fout(cfgPath, std::ios::trunc);
1662 if (!fout.is_open()) {
1663 std::cerr <<
"[Backend] ❌ " <<
_(
"Impossibile aprire il file di configurazione per scrittura: ")
1668 fout <<
"# " <<
_(
"Configurazione Google Safe Browsing") <<
"\n";
1673 std::cout <<
"[Backend] ✔ " <<
_(
"Configurazione Google Safe salvata in ") << cfgPath <<
"\n";
1674 }
catch (
const std::exception& ex) {
1675 std::cerr <<
"[Backend] ⚠ " <<
_(
"Errore durante il salvataggio della configurazione Google Safe: ")
1676 << ex.what() <<
"\n";
1682 std::cerr <<
"[Backend] ❌ " <<
_(
"Nessuna chiave API Google Safe impostata") <<
"\n";
1686 CURL* curl = curl_easy_init();
1688 std::cerr <<
"[Backend] ⚠ " <<
_(
"Impossibile inizializzare la libreria CURL") <<
"\n";
1692 std::string url =
"https://safebrowsing.googleapis.com/v4/threatLists?key=" +
googleSafeApiKey_;
1693 std::string response;
1695 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
1696 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10L);
1697 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
1698 curl_easy_setopt(curl, CURLOPT_USERAGENT,
"BastionGuard/1.0");
1700 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
1701 +[](
void* contents,
size_t size,
size_t nmemb,
void* userp) ->
size_t {
1702 ((std::string*)userp)->append((
char*)contents, size * nmemb);
1703 return size * nmemb;
1705 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
1707 CURLcode res = curl_easy_perform(curl);
1709 if (res != CURLE_OK) {
1710 std::cerr <<
"[Backend] ⚠ " <<
_(
"Errore nella richiesta HTTP a Google Safe: ")
1711 << curl_easy_strerror(res) <<
"\n";
1712 curl_easy_cleanup(curl);
1716 curl_easy_cleanup(curl);
1718 if (response.find(
"threatType") != std::string::npos) {
1719 std::cout <<
"[Backend] ✔ " <<
_(
"Chiave Google Safe valida e attiva") <<
"\n";
1722 std::cerr <<
"[Backend] ❌ " <<
_(
"Chiave API non valida o risposta inattesa dal server") <<
"\n";
1728 int ret = (
bg_process::run({
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"is-enabled",
"BastionGuard-phishing-updater.timer"}).exit_code);
1733 int ret =
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
1734 "--system", enable ?
"enable" :
"disable",
"--now",
"BastionGuard-phishing-updater.timer"}).exit_code;
1738 std::cout <<
"✔ " <<
_(
"Timer aggiornamento phishing attivato correttamente.") << std::endl;
1740 std::cout <<
"ℹ️ " <<
_(
"Timer aggiornamento phishing disattivato.") << std::endl;
1745 std::cerr <<
"❌ " <<
_(
"Errore durante l’attivazione del timer di aggiornamento phishing!") << std::endl;
1747 std::cerr <<
"⚠️ " <<
_(
"Errore durante la disattivazione del timer di aggiornamento phishing!") << std::endl;
1755 const char* home = getenv(
"HOME");
1756 if (!home)
return "/tmp/BastionGuard/samba.conf";
1758 std::string cfgDir = std::string(home) +
"/.config/BastionGuard";
1759 std::filesystem::create_directories(cfgDir);
1761 return cfgDir +
"/samba.conf";
1766 std::vector<std::string> out;
1768 if (!f.is_open())
return out;
1771 while (std::getline(f, line))
1774 if (line.empty())
continue;
1775 if (line ==
"enabled=true" || line ==
"enabled=false")
continue;
1777 out.push_back(line);
1785 namespace fs = std::filesystem;
1788 if (!fs::exists(dir, ec) || !fs::is_directory(dir, ec))
1792 auto probe = dir /
".bastionguard_write_test";
1794 std::ofstream out(probe, std::ios::out | std::ios::trunc);
1799 fs::remove(probe, ec);
1805 namespace fs = std::filesystem;
1809 fs::path candidates[] = {
1810 fs::temp_directory_path(),
1811 fs::path(
"/var/tmp")
1814 auto ensure_dir_ok = [&](
const fs::path& p) ->
bool {
1816 if (!fs::exists(p, ec))
1818 if (!fs::is_directory(p, ec))
1826 for (
const auto& c : candidates) {
1827 if (ensure_dir_ok(c)) {
1835 std::random_device rd;
1836 std::mt19937_64 gen(rd());
1837 std::uniform_int_distribution<unsigned long long> dis(1, ULLONG_MAX);
1839 for (
int tries = 0; tries < 60; ++tries) {
1840 fs::path tmp = base / (
"BastionGuard_samba_" + std::to_string(dis(gen)));
1843 if (!fs::create_directories(tmp, ec) || ec)
1847 fs::permissions(tmp,
1848 fs::perms::owner_all |
1849 fs::perms::group_read | fs::perms::group_exec |
1850 fs::perms::others_read | fs::perms::others_exec,
1851 fs::perm_options::replace,
1855 fs::remove_all(tmp, ec);
1862 fs::remove_all(tmp, ec);
1873 SMBCCTX* ctx = smbc_new_context();
1874 if (!ctx)
return nullptr;
1876 smbc_setOptionUseKerberos(ctx,
false);
1878 smbc_setOptionUserData(ctx,
this);
1880 if (!smbc_init_context(ctx)) {
1881 smbc_free_context(ctx, 1);
1894 char* wg,
int wglen,
1895 char* un,
int unlen,
1896 char* pw,
int pwlen)
1898 std::string key =
"smb://" + std::string(srv) +
"/" + std::string(shr);
1902 std::string user = creds.first;
1903 std::string pass = creds.second;
1905 if (user.empty()) user =
"guest";
1906 if (pass.empty()) pass =
"";
1908 strncpy(un, user.c_str(), unlen - 1);
1909 un[unlen - 1] =
'\0';
1911 strncpy(pw, pass.c_str(), pwlen - 1);
1912 pw[pwlen - 1] =
'\0';
1914 strncpy(wg,
"WORKGROUP", wglen - 1);
1915 wg[wglen - 1] =
'\0';
1922 if (url.rfind(
"smb://", 0) != 0)
1926 std::regex re(R
"(smb:\/\/[^\/]+\/[^\/]+)");
1927 return std::regex_search(url, re);
1931 const std::string& user,
1932 const std::string& pass)
1935 std::regex re(R
"(smb:\/\/([^\/]+)\/([^\/]+))");
1938 std::string key = url;
1939 if (std::regex_search(url, m, re)) {
1940 key =
"smb://" + m[1].str() +
"/" + m[2].str();
1947 std::ifstream fin(path);
1949 std::map<std::string,std::pair<std::string,std::string>> all;
1952 if (fin.is_open()) {
1956 while (std::getline(fin, line)) {
1957 if (line.empty())
continue;
1959 if (line[0] ==
'[' && line.back() ==
']') {
1960 cur = line.substr(1, line.size()-2);
1963 else if (line.find(
"user=") == 0) {
1966 else if (line.find(
"pass=") == 0) {
1974 all[key] = { user, pass };
1977 std::ofstream fout(path, std::ios::trunc);
1978 if (!fout.is_open()) {
1979 std::cerr <<
_(
"❌ Impossibile scrivere credenziali SMB\n");
1983 for (
auto &kv : all) {
1984 fout <<
"[" << kv.first <<
"]\n";
1985 fout <<
"user=" <<
b64_encode(kv.second.first) <<
"\n";
1986 fout <<
"pass=" <<
encrypt_pass(kv.second.second) <<
"\n\n";
1990 std::cout <<
_(
"✔ Credenziali SMB salvate in modo sicuro (XOR + Base64)\n");
1998 std::ifstream fin(path);
2002 std::string line, cur;
2004 while (std::getline(fin, line)) {
2005 if (line.empty())
continue;
2007 if (line[0] ==
'[' && line.back() ==
']') {
2008 cur = line.substr(1, line.size()-2);
2011 else if (line.find(
"user=") == 0) {
2014 else if (line.find(
"pass=") == 0) {
2021 std::cout <<
_(
"✔ Credenziali SMB caricate: ")
2027std::pair<std::string,std::string>
2031 std::ifstream f(path);
2039 std::string user, pass;
2041 while (std::getline(f, line)) {
2042 if (line.empty())
continue;
2044 if (line ==
"[" + url +
"]") {
2050 if (line.rfind(
"user=", 0) == 0)
2053 else if (line.rfind(
"pass=", 0) == 0)
2056 if (!user.empty() && !pass.empty())
2057 return { user, pass };
2068 if (path.rfind(
"smb://", 0) == 0)
2077 const std::string& url,
2078 std::vector<std::string>& out)
2081 std::cerr <<
_(
"SMB ERROR: contesto SMB nullo\n");
2093 const std::string& url,
2094 std::vector<std::string>& out)
2097 std::cerr <<
"SMB ERROR: ctx NULL in smb_collect_files_impl\n";
2102 auto fn_opendir = smbc_getFunctionOpendir(ctx);
2103 auto fn_readdir = smbc_getFunctionReaddir(ctx);
2104 auto fn_closedir = smbc_getFunctionClosedir(ctx);
2106 if (!fn_opendir || !fn_readdir || !fn_closedir) {
2107 std::cerr <<
_(
"SMB ERROR: funzioni SMB mancanti (contesto non valido)\n");
2112 SMBCFILE* dir = fn_opendir(ctx, url.c_str());
2115 std::cerr <<
_(
"SMB ERROR: impossibile aprire ") << url
2116 <<
" (errno=" << err <<
")\n";
2120 struct smbc_dirent* ent =
nullptr;
2123 while ((ent = fn_readdir(ctx, dir)) !=
nullptr)
2127 const char* name = ent->name;
2128 if (!name || name[0] ==
'.')
continue;
2130 std::string full = url;
2131 if (full.back() !=
'/')
2135 switch (ent->smbc_type)
2138 out.push_back(full);
2150 fn_closedir(ctx, dir);
2155 const std::string& smbPath,
2156 std::function<
bool(
const char*,
size_t)> onChunk)
2159 std::cerr <<
_(
"SMB ERROR: ctx nullo\n");
2164 auto fn_open = smbc_getFunctionOpen (ctx);
2165 auto fn_read = smbc_getFunctionRead (ctx);
2166 auto fn_close = smbc_getFunctionClose (ctx);
2168 if (!fn_open || !fn_read || !fn_close)
2170 std::cerr <<
_(
"SMB ERROR: funzioni SMB non disponibili\n");
2175 SMBCFILE* fd = fn_open(ctx, smbPath.c_str(), O_RDONLY, 0);
2177 std::cerr <<
_(
"SMB ERROR: impossibile aprire file: ") << smbPath <<
"\n";
2184 while ((n = fn_read(ctx, fd, buffer,
sizeof(buffer))) > 0)
2186 if (!onChunk(buffer, (
size_t)n))
2188 std::cerr <<
_(
"SMB ERROR: callback fallita\n");
2201 const std::filesystem::path& dest)
2203 namespace fs = std::filesystem;
2207 std::cerr <<
_(
"SMB ERROR: impossibile creare contesto SMB\n");
2213 fs::create_directories(dest.parent_path(), ec);
2215 std::cerr <<
_(
"SMB ERROR: impossibile creare directory ")
2216 << dest.parent_path().string()
2217 <<
" (" << ec.message() <<
")\n";
2218 smbc_free_context(ctx, 1);
2222 fs::permissions(dest.parent_path(),
2223 fs::perms::owner_all |
2224 fs::perms::group_read | fs::perms::group_exec |
2225 fs::perms::others_read | fs::perms::others_exec,
2226 fs::perm_options::add,
2230 std::ofstream out(dest, std::ios::binary | std::ios::trunc);
2231 if (!out.is_open()) {
2232 std::cerr <<
_(
"SMB ERROR: impossibile aprire file locale ")
2233 << dest.string() <<
_(
" per scrittura\n");
2234 smbc_free_context(ctx, 1);
2241 [&](
const char* data,
size_t n) ->
bool
2243 out.write(data,
static_cast<std::streamsize
>(n));
2251 smbc_free_context(ctx, 1);
2254 std::cerr <<
_(
"SMB ERROR: copia fallita per: ") << smbPath <<
"\n";
2255 std::error_code ec2;
2256 fs::remove(dest, ec2);
2261 fs::permissions(dest,
2262 fs::perms::owner_read | fs::perms::owner_write |
2263 fs::perms::group_read |
2264 fs::perms::others_read,
2265 fs::perm_options::replace,
2282 namespace fs = std::filesystem;
2290 std::string scanPath =
trim(dirInput);
2293 std::string originalSmbRoot = scanPath;
2294 if (!originalSmbRoot.empty() && originalSmbRoot.back() ==
'/')
2295 originalSmbRoot.pop_back();
2298 if (scanPath.rfind(
"smb://", 0) == 0)
2300 if (scanPath.back() !=
'/')
2304 auto push_log = [&](
const std::string& s)
2311 push_log(
_(
"=== Scansione Samba: ") + scanPath +
" ===");
2313 bool isSmb = scanPath.rfind(
"smb://", 0) == 0;
2315 std::vector<fs::path> files;
2316 std::vector<std::string> smbFiles;
2318 SMBCCTX* ctx =
nullptr;
2323 push_log(
_(
"Percorso SMB rilevato. Creo contesto SMB..."));
2328 push_log(
_(
"ERRORE: impossibile creare contesto SMB."));
2335 if (smbFiles.empty())
2337 push_log(
_(
"ERRORE: impossibile elencare la share SMB."));
2342 for (
auto& f : smbFiles)
2345 push_log(
_(
"File trovati via SMB: ") + std::to_string(files.size()));
2350 if (!fs::exists(scanPath))
2352 push_log(
_(
"ERRORE: directory locale non trovata."));
2360 fs::recursive_directory_iterator(scanPath, fs::directory_options::skip_permission_denied))
2362 if (e.is_regular_file())
2363 files.push_back(e.path());
2368 push_log(
_(
"ERRORE: impossibile scansionare la directory locale."));
2373 push_log(
_(
"Nessun file da scansionare."));
2378 push_log(
_(
"File trovati localmente: ") + std::to_string(files.size()));
2383 std::string clamdscanPath;
2384 const char* paths[] = {
2385 "/usr/bin/clamdscan",
2386 "/usr/local/bin/clamdscan",
2389 for (
auto p : paths)
2390 if (fs::exists(p)) { clamdscanPath = p;
break; }
2392 if (clamdscanPath.empty()) {
2393 push_log(
_(
"ERRORE: clamdscan non trovato."));
2402 push_log(
_(
"ERRORE: il demone clamd non è attivo."));
2407 push_log(
_(
"Demone ClamAV rilevato."));
2415 if (tempDir.empty()) {
2416 push_log(
_(
"ERRORE: impossibile determinare una directory temporanea valida (path vuoto)."));
2422 if (!fs::exists(tempDir, ec) || ec) {
2423 push_log(
_(
"ERRORE: directory temporanea non esistente o non accessibile: ") + tempDir.string());
2424 if (ec) push_log(std::string(
"std::filesystem error: ") + ec.message());
2429 if (!fs::is_directory(tempDir, ec) || ec) {
2430 push_log(
_(
"ERRORE: path temporaneo non è una directory valida: ") + tempDir.string());
2431 if (ec) push_log(std::string(
"std::filesystem error: ") + ec.message());
2444 size_t total = files.size();
2447 push_log(
_(
"Trovati ") + std::to_string(total) +
_(
" file da copiare."));
2449 for (
const auto& src : files)
2457 fs::path rel = fs::relative(src, scanPath);
2458 dest = tempDir / rel;
2460 fs::create_directories(dest.parent_path());
2463 fs::copy_file(src, dest, fs::copy_options::overwrite_existing, ec);
2466 push_log(
_(
"ERRORE copia locale: ") + rel.string());
2472 std::string smbFile = src.string();
2474 std::string relative = smbFile.substr(scanPath.size());
2475 if (!relative.empty() && relative[0] ==
'/')
2476 relative.erase(0,1);
2478 dest = tempDir / relative;
2479 fs::create_directories(dest.parent_path());
2484 [&](
const char* data,
size_t n)
2486 std::ofstream out(dest, std::ios::binary | std::ios::app);
2487 if (!out.is_open())
return false;
2495 push_log(
_(
"ERRORE lettura SMB: ") + smbFile);
2504 push_log(
_(
"Copiato: ") + src.string());
2514 push_log(
_(
"Eseguo scansione ClamAV: ") + tempDir.string());
2516 auto scan =
bg_process::run({clamdscanPath,
"--fdpass",
"--no-summary",
"--multiscan",
2517 "--", tempDir.string()},
true, 32U * 1024U * 1024U, {},
2518 [&](
const std::string& line) {
2521 push_log(
"ClamAV: " + line);
2523 std::string filename = line.substr(0, line.find(
':'));
2526 if (line.find(
"FOUND") != std::string::npos)
2528 fs::path tmpFile = filename;
2529 fs::path rel = fs::relative(tmpFile, tempDir);
2532 std::string orig = originalSmbRoot +
"/" + rel.string();
2535 push_log(
"INFETTO: " + orig);
2544 if (!scan.started || scan.truncated) push_log(
_(
"ERRORE: scansione ClamAV non completata."));
2545 std::this_thread::sleep_for(std::chrono::milliseconds(300));
2553 push_log(
_(
"=== Scansione completata ==="));
2554 push_log(
_(
"File analizzati: ") + std::to_string(files.size()));
2560 try { fs::remove_all(tempDir); }
catch (...) {}
2580 auto it = std::remove(dirs.begin(), dirs.end(), dir);
2581 if (it == dirs.end()) {
2582 std::cerr <<
"⚠️ " <<
_(
"Directory Samba non trovata: ") << dir <<
"\n";
2586 dirs.erase(it, dirs.end());
2594 std::cerr <<
_(
"⚠️ Impossibile riscrivere la configurazione Samba\n");
2598 f <<
"enabled=" << (enabled ?
"true" :
"false") <<
"\n";
2601 for (
const auto& d : dirs)
2604 std::cout <<
"✔ " <<
_(
"Rimossa directory Samba: ") << dir <<
"\n";
2611 f <<
"enabled=" << (enabled ?
"true" :
"false") <<
"\n";
2613 for (
auto& d : dirs)
2614 f <<
trim(d) <<
"\n";
2622 std::cout <<
_(
"🔧 Inizializzazione canale D-Bus per invio alert...") << std::endl;
2625 auto connection = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::SESSION);
2628 auto result = connection->call_sync(
2629 "/org/freedesktop/DBus",
2630 "org.freedesktop.DBus",
2632 Glib::VariantContainerBase::create_tuple({
2633 Glib::Variant<Glib::ustring>::create(
"org.BastionGuard.Ransomware.Alert")
2635 "org.freedesktop.DBus",
2637 Gio::DBus::CallFlags::NONE,
2641 bool listener_attivo =
false;
2642 if (result.gobj() !=
nullptr) {
2643 Glib::Variant<bool> active;
2644 result.get_child(active, 0);
2645 listener_attivo = active.get();
2648 if (listener_attivo)
2649 std::cout <<
_(
"🟢 Servizio BastionGuard-ransomware-alert trovato su D-Bus.") << std::endl;
2651 std::cerr <<
_(
"⚠️ Servizio BastionGuard-ransomware-alert non attivo. Gli avvisi non verranno mostrati.") << std::endl;
2653 }
catch (
const Glib::Error& ex) {
2654 std::cerr <<
_(
"❌ Errore inizializzazione D-Bus: ") << ex.what() << std::endl;
2661 auto conn = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::SESSION);
2664 auto args = Glib::VariantContainerBase::create_tuple({
2665 Glib::Variant<Glib::ustring>::create(
"org.BastionGuard.Ransomware.Alert")
2668 bool nameHasOwner =
false;
2670 auto reply = conn->call_sync(
2671 "/org/freedesktop/DBus",
2672 "org.freedesktop.DBus",
2675 "org.freedesktop.DBus"
2678 Glib::Variant<bool> result;
2679 reply.get_child(result, 0);
2680 nameHasOwner = result.get();
2681 }
catch (
const Glib::Error& ex) {
2682 std::cerr <<
_(
"⚠️ Impossibile verificare il listener D-Bus: ")
2683 << ex.what() << std::endl;
2686 if (!nameHasOwner) {
2687 std::cerr <<
_(
"⚠️ Listener org.BastionGuard.Ransomware.Alert non attivo — nessun popup verrà mostrato.") << std::endl;
2692 auto parameters = Glib::VariantContainerBase::create_tuple({
2693 Glib::Variant<Glib::ustring>::create(path),
2694 Glib::Variant<Glib::ustring>::create(family)
2699 "/org/BastionGuard/ransomware/alert",
2700 "org.BastionGuard.Ransomware.Alert",
2703 "org.BastionGuard.Ransomware.Alert",
2705 Gio::DBus::CallFlags::NONE,
2709 std::cout << Glib::ustring::compose(
2710 _(
"📢 Alert ransomware inviato via D-Bus:\n - File: %1\n - Famiglia: %2"),
2714 catch (
const Glib::Error& ex) {
2715 std::cerr <<
_(
"❌ Errore nell'invio alert D-Bus: ") << ex.what() << std::endl;
2728 Glib::signal_idle().connect_once([path, moved]() {
2732 _(
"File spostato in quarantena con successo:\n") + path,
2733 Gtk::MessageType::INFO);
2737 _(
"Impossibile spostare l'elemento in quarantena. "
2738 "Sono accettati esclusivamente file regolari:\n") + path,
2739 Gtk::MessageType::ERROR);
2749 if (quarantineDir.empty()) {
2750 quarantineDir =
"/var/lib/clamav/quarantine";
2753 std::filesystem::path qPath(quarantineDir);
2755 if (!std::filesystem::exists(qPath)) {
2756 std::filesystem::create_directories(qPath);
2757 std::cout <<
_(
"📁 Creata directory di quarantena: ") << qPath <<
"\n";
2761 std::filesystem::permissions(qPath,
2762 std::filesystem::perms::owner_all |
2763 std::filesystem::perms::group_read |
2764 std::filesystem::perms::group_write,
2765 std::filesystem::perm_options::replace
2767 }
catch (
const std::exception& ex) {
2768 std::cerr <<
_(
"❌ Errore in ensureQuarantinePath(): ") << ex.what() <<
"\n";
2784 for (
const auto& dir : dirs)
2799static size_t write_cb(
void* c,
size_t s,
size_t n, std::string* o) {
2800 o->append((
char*)c, s * n);
2806 if (url.rfind(
"https://", 0) != 0) {
2807 std::cerr <<
_(
"[Backend] ❌ La lista banche deve essere scaricata via HTTPS.\n");
2811 std::string dir = Glib::get_home_dir() +
"/.local/share/BastionGuard";
2812 std::string path = dir +
"/banks.json";
2813 std::string tmp_path = path +
".download";
2814 std::filesystem::create_directories(dir);
2815 std::error_code cleanup_ec;
2816 std::filesystem::remove(tmp_path, cleanup_ec);
2818 CURL* curl = curl_easy_init();
2820 std::cerr <<
_(
"[Backend] ❌ Errore: init cURL\n");
2824 std::ofstream outfile(tmp_path, std::ios::binary | std::ios::trunc);
2825 if (!outfile.is_open()) {
2826 std::cerr <<
_(
"[Backend] ❌ Errore apertura file temporaneo ") << tmp_path <<
"\n";
2827 curl_easy_cleanup(curl);
2831 std::cout <<
_(
"[Backend] 🌍 Download da URL: ") << url << std::endl;
2833 curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
2834 curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
2835 curl_easy_setopt(curl, CURLOPT_USERAGENT,
"BastionGuard/1.0");
2836 curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L);
2837 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 25L);
2838 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
2839 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
2840 curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
2841 curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
2843 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &outfile);
2844 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,
2845 +[](
void* ptr,
size_t size,
size_t nmemb,
void* stream) ->
size_t {
2846 std::ofstream* out =
static_cast<std::ofstream*
>(stream);
2847 out->write(
static_cast<const char*
>(ptr), size * nmemb);
2848 return size * nmemb;
2851 CURLcode res = curl_easy_perform(curl);
2852 long response_code = 0;
2853 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
2856 curl_easy_cleanup(curl);
2858 std::cout <<
_(
"[Backend] Risultato cURL: ") << res <<
" (" << curl_easy_strerror(res) <<
"), HTTP " << response_code <<
"\n";
2860 if (res != CURLE_OK || response_code != 200) {
2861 std::cerr <<
_(
"[Backend] ❌ Errore rete o HTTP (") << curl_easy_strerror(res) <<
")\n";
2862 std::error_code ec; std::filesystem::remove(tmp_path, ec);
2866 if (!std::filesystem::exists(tmp_path) || std::filesystem::file_size(tmp_path) < 50) {
2867 std::cerr <<
_(
"[Backend] ⚠ banks.json scaricato ma vuoto.\n");
2868 std::error_code ec; std::filesystem::remove(tmp_path, ec);
2874 std::ifstream check(tmp_path);
2877 if (!j.is_object() || !j.contains(
"list") || !j[
"list"].is_array() || j[
"list"].empty()) {
2878 std::cerr <<
_(
"[Backend] ❌ banks.json non ha una struttura valida.\n");
2879 std::error_code ec; std::filesystem::remove(tmp_path, ec);
2882 for (
const auto& item : j[
"list"]) {
2883 if (item.is_string())
continue;
2884 if (item.is_object() && item.contains(
"value") && item[
"value"].is_string())
continue;
2885 std::cerr <<
_(
"[Backend] ❌ banks.json contiene una voce non valida.\n");
2886 std::error_code ec; std::filesystem::remove(tmp_path, ec);
2890 std::cerr <<
_(
"[Backend] ❌ banks.json non è JSON valido.\n");
2891 std::error_code ec; std::filesystem::remove(tmp_path, ec);
2895 std::error_code replace_ec;
2896 std::filesystem::rename(tmp_path, path, replace_ec);
2898 std::cerr <<
_(
"[Backend] ❌ Impossibile sostituire banks.json: ") << replace_ec.message() <<
"\n";
2899 std::filesystem::remove(tmp_path, cleanup_ec);
2903 std::cout <<
_(
"[Backend] ✅ Lista banche aggiornata (") << std::filesystem::file_size(path) <<
" bytes)\n";
2914 if (domain.empty())
return;
2932 std::filesystem::create_directories(Glib::get_home_dir() +
"/.config/BastionGuard");
2933 std::ofstream f(Glib::get_home_dir() +
"/.config/BastionGuard/whitelist.json", std::ios::trunc);
2937 std::cout <<
_(
"✔ Whitelist salvata (") <<
whitelist_.size() <<
" voci)\n";
2938 }
catch (
const std::exception& e) {
2939 std::cerr <<
_(
"❌ Errore salvataggio whitelist: ") << e.what() << std::endl;
2945 std::string path = Glib::get_home_dir() +
"/.config/BastionGuard/whitelist.json";
2946 if (!std::filesystem::exists(path))
return;
2949 std::ifstream f(path);
2953 for (
auto& item : j)
2954 whitelist_.push_back(item.get<std::string>());
2956 std::cout <<
_(
"✔ Whitelist caricata (") <<
whitelist_.size() <<
" voci)\n";
2957 }
catch (
const std::exception& e) {
2958 std::cerr <<
_(
"⚠ Errore caricamento whitelist: ") << e.what() << std::endl;
2967 int ret = (
bg_process::run({
"pkexec",
"/usr/libexec/bastionguard/bastionguard-service",
"--system",
"reload",
"dnsmasq.service"}).exit_code);
2969 std::cout <<
_(
"✔ dnsmasq ricaricato correttamente.\n");
2972 std::cerr <<
_(
"⚠️ Errore nel reload di dnsmasq.\n");
2978 std::cout <<
_(
"[Backend] setPhishingPort(") << port <<
_(
") — funzione non più usata.") << std::endl;
3004 const std::vector<std::string>& blacklistLines,
3005 std::string& outPath
3007 std::string pathTemplate =
"/tmp/bastionguard-firewall-ips-XXXXXX";
3008 std::vector<char> pathBuffer(pathTemplate.begin(), pathTemplate.end());
3009 pathBuffer.push_back(
'\0');
3011 const int fd = ::mkstemp(pathBuffer.data());
3013 std::cerr <<
_(
"[Firewall] Impossibile creare il file temporaneo sicuro\n");
3017 outPath.assign(pathBuffer.data());
3021 ::unlink(outPath.c_str());
3023 std::cerr <<
_(
"[Firewall] Impossibile proteggere il file temporaneo\n");
3030 ::unlink(outPath.c_str());
3039 ::unlink(outPath.c_str());
3041 std::cerr <<
_(
"[Firewall] Impossibile impostare i permessi del file temporaneo\n");
3046 if (::lstat(outPath.c_str(), &st) != 0 ||
3047 !S_ISREG(st.st_mode) ||
3048 st.st_uid != ::getuid() ||
3051 ::unlink(outPath.c_str());
3053 std::cerr <<
_(
"[Firewall] File temporaneo non sicuro\n");
3061 const pid_t pid = ::fork();
3069 "/usr/bin/bastionguard-firewall",
3072 static_cast<char*
>(
nullptr)
3078 while (::waitpid(pid, &status, 0) < 0) {
3084 if (!WIFEXITED(status))
3087 return WEXITSTATUS(status);
3093 const std::vector<std::string>& blacklistLines
3098 std::string outPath;
3099 if (!create_secure_firewall_input(blacklistLines, outPath)) {
3100 std::cout <<
_(
"[Firewall] Nessun IP valido estratto\n");
3136 const char* home = std::getenv(
"HOME");
3139 std::ifstream fin(std::string(home) +
"/.config/BastionGuard/firewall.conf");
3143 while (std::getline(fin, line)) {
3144 if (line ==
"firewall_enabled=true")
3146 else if (line ==
"firewall_enabled=false")
3148 else if (line ==
"firewall_type=firewalld")
3150 else if (line ==
"firewall_type=ufw")
3156 const char* home = std::getenv(
"HOME");
3160 fout.open(std::string(home) +
"/.config/BastionGuard/firewall.conf");
3162 fout <<
"firewall_enabled=" << (
firewallEnabled_ ?
"true" :
"false") <<
"\n";
3166 fout <<
"firewall_type=firewalld\n";
break;
3168 fout <<
"firewall_type=ufw\n";
break;
3179 const std::string blacklistPath =
3180 "/usr/share/BastionGuard/data/phishing/blacklist.txt";
3182 std::ifstream fin(blacklistPath);
3184 std::cerr <<
_(
"[Firewall] Impossibile aprire blacklist\n");
3188 std::vector<std::string> lines;
3190 while (std::getline(fin, line))
3191 lines.push_back(line);
3196 std::string outPath;
3197 if (!create_secure_firewall_input(lines, outPath)) {
3198 std::cout <<
_(
"[Firewall] Nessun IP valido trovato\n");
3208 static std::atomic<bool> pending{
false};
3210 if (pending.exchange(
true)) {
3211 ::unlink(inputPath.c_str());
3215 std::thread([inputPath] {
3216 std::this_thread::sleep_for(std::chrono::seconds(2));
3218 const int exitCode = run_firewall_helper(inputPath);
3219 if (exitCode != 0) {
3220 std::cerr <<
_(
"[Firewall] Applicazione helper fallita, codice: ")
3221 << exitCode <<
"\n";
3222 ::unlink(inputPath.c_str());
3225 pending.store(
false);
static std::string extract_path_from_clamav_line(const std::string &line)
static std::string decrypt_pass(const std::string &enc)
static int installPackages(const std::vector< std::string > &args)
static bool is_writable_dir(const std::filesystem::path &dir)
static std::string encrypt_pass(const std::string &pass)
static const std::string SMB_KEY
static std::string first_existing(const std::vector< std::string > &names)
static std::string getConfigFilePath()
static size_t write_cb(void *c, size_t s, size_t n, std::string *o)
static std::string quarantinePath
sigc::signal< void(const std::string &)> antiphish_signal_
static bool copy_to_final(const std::string &src, const std::string &dest)
static std::vector< std::string > clamDbDirs()
static void ensureQuarantinePath()
static std::string detectDistro()
static bool isClamdInstalled()
static std::filesystem::path make_temp_scan_dir()
static std::string xor_crypt(const std::string &input)
static std::string trim(const std::string &s)
static std::string findClamonaccService()
std::pair< int, int > read_ports_from_conf()
static bool run_phishing_updater_script(const std::string &staging_dir)
static std::string b64_encode(const std::string &s)
static std::string b64_decode(const std::string &s)
static void restart_clamd()
static bool install_to_system_data(const std::string &src, const std::string &dest)
static std::string getUserConfigDir()
static const char * CLAMONACC_SERVICES[]
static void persistQuarantinePath(const std::string &path)
static bool read_cvd_header(const std::string &path, DbInfo &out)
static void loadQuarantinePathFromConfig()
static std::string getRuntimeDataDir()
static std::time_t filetime_to_time_t(fs::file_time_type ft)
std::function< void(const std::string &, float)> samba_progress_callback
static std::string resolveSambaDir(const std::string &path)
AntiRansomEngine antiransom_
bool isFirewallEnabled() const
std::vector< std::string > whitelist_
bool isSambaScanRunning()
bool isBankDomain(const std::string &host) const
bool removeSambaDir(const std::string &dir)
static std::vector< std::string > getOnAccessEvents()
static std::vector< std::string > getOnAccessPaths()
static std::vector< std::string > getClamonaccLogs()
std::string samba_last_temp_dir
bool smb_copy_file(const std::string &smbPath, const std::filesystem::path &dest)
void addToWhitelist(const std::string &domain)
void loadSMBCredentials()
void requestStopSambaScan()
bool enablePhishAutoUpdate(bool enable)
std::atomic< bool > samba_stop_requested
static bool isAntiransomActive()
void scheduleFirewallApply(const std::string &inputPath)
std::string getSambaCredsPath() const
static std::string getAppVersion()
void saveSambaConfig(bool enabled, const std::vector< std::string > &dirs)
void setFirewallEnabled(bool enabled)
float samba_last_progress
sigc::signal< void(const std::string &)> antiransom_signal_
void setSambaEnabled(bool enabled)
static std::string getQuarantinePath()
std::string checkUrl(const std::string &url)
static void smb_auth_fn(SMBCCTX *context, const char *srv, const char *shr, char *wg, int wglen, char *un, int unlen, char *pw, int pwlen)
void smb_collect_files(SMBCCTX *ctx, const std::string &url, std::vector< std::string > &out)
static void setQuarantinePath(const std::string &path)
bool updateYaraRules(std::function< void(int, int, const std::string &)> progressCallback=nullptr)
void ensureQuarantinePath()
static Backend & instance()
int getPhishingPort() const
bool updateBankListFromURL(const std::string &source_url)
void loadFirewallConfig()
std::unique_ptr< WebProbe > webprobe_
void setupAlertListener()
static bool isValidSMB(const std::string &url)
sigc::signal< void(const std::string &)> & signal_antiphish_event()
void removeFromWhitelist(const std::string &domain)
std::string googleSafeApiKey_
void setPhishingPort(int port)
std::pair< std::string, std::string > getCreds(const std::string &url)
ScanStatus get_current_scan_files()
void sendRansomwareAlert(const std::string &path, const std::string &family)
SMBCCTX * createThreadSmbContext()
void applyFirewallFromBlacklist(const std::vector< std::string > &blacklistLines)
static std::string getClamonaccStatus()
static std::string getLastUpdateDate()
FirewallType getFirewallType() const
void moveToQuarantine(const std::string &)
bool updateSanesecurityDB(std::function< void(int, int, const std::string &)> progressCallback=nullptr)
void mergeWhitelistSources()
std::vector< std::string > getSambaDirs()
std::string getSambaConfigPath() const
void setFirewallType(FirewallType fw)
void saveSMBCredentials(const std::string &url, const std::string &user, const std::string &pass)
static bool isClamonaccActive()
std::map< std::string, std::pair< std::string, std::string > > smb_credentials
static bool disableClamonacc()
void scanSambaDir(const std::string &dir)
void saveWhitelist() const
void saveFirewallConfig() const
FirewallType firewallType_
sigc::signal< void(const std::string &)> & signal_antiransom_event()
bool isPhishAutoUpdateEnabled()
void applyFirewallFromPhishingBlacklist()
void saveGoogleSafeConfig()
bool smb_read_file_with_ctx(SMBCCTX *ctx, const std::string &smbPath, std::function< bool(const char *, size_t)>)
SambaScanState samba_scan_state
void smb_collect_files_impl(SMBCCTX *ctx, const std::string &url, std::vector< std::string > &out)
std::vector< std::string > getWhitelist() const
static bool enableClamonacc()
static bool installClamdIfMissing()
static std::string getDbVersion()
static FirewallType detectFirewall()
static bool move(const std::string &file)
static void show_message(Gtk::Window *parent, const std::string &message, Gtk::MessageType type=Gtk::MessageType::INFO, const std::string &secondary=std::string())
bool create_secure_firewall_input(const std::vector< std::string > &blacklistLines, std::string &outPath)
int run_firewall_helper(const std::string &inputPath)
Result run(const std::vector< std::string > &args, bool merge_stderr=false, std::size_t limit=8U *1024U *1024U, const std::map< std::string, std::string > &environment={}, const std::function< bool(const std::string &)> &on_line={})
bool exists_on_path(const std::string &name)
std::string resource(const std::string &rel)
std::vector< std::string > log
std::vector< std::string > files
std::string current_scanning