362 lines
11 KiB
C++
362 lines
11 KiB
C++
/*
|
|
* BastionGuard™
|
|
* Copyright (C) 2025–2026 Calogero Scarnà
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*
|
|
* BastionGuard™ is a trademark of Calogero Scarnà.
|
|
* The BastionGuard™ name and branding are not licensed under the GPL.
|
|
*/
|
|
|
|
#include "PacManager.hpp"
|
|
#include "../SafeProcess.hpp"
|
|
#include <cstdlib>
|
|
#include <unistd.h>
|
|
#include <cstdio>
|
|
#include <array>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <glib/gi18n.h>
|
|
#include <glibmm/miscutils.h>
|
|
#include <glibmm/shell.h>
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
bool PacManager::cmd_exists(const std::string& cmd) {
|
|
if (cmd.empty()) return false;
|
|
if (cmd.find('/') != std::string::npos) return access(cmd.c_str(), X_OK) == 0;
|
|
const char* configured_path = std::getenv("PATH");
|
|
std::istringstream dirs(configured_path ? configured_path : "/usr/local/bin:/usr/bin:/bin");
|
|
std::string dir;
|
|
while (std::getline(dirs, dir, ':')) {
|
|
if (dir.empty()) dir = ".";
|
|
if (access((fs::path(dir) / cmd).c_str(), X_OK) == 0) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static bool run_user_servicectl(const std::vector<std::string>& args) {
|
|
std::vector<std::string> command = {
|
|
"/usr/libexec/bastionguard/bastionguard-service", "--user"};
|
|
command.insert(command.end(), args.begin(), args.end());
|
|
return bg_process::run(command).ok();
|
|
}
|
|
|
|
PacManager::Result PacManager::start_pacd_user() {
|
|
Result r; r.backend = "user-service-manager";
|
|
|
|
if (!cmd_exists("/usr/libexec/bastionguard/bastionguard-service")) {
|
|
r.message = _("gestore servizi BastionGuard non disponibile");
|
|
return r;
|
|
}
|
|
|
|
if (run_user_servicectl({"daemon-reload"}) &&
|
|
run_user_servicectl({"enable", "--now", "BastionGuard-pacd.service"})) {
|
|
r.ok = true;
|
|
r.message = _("bastionguard-pacd avviato (servizio utente)");
|
|
return r;
|
|
}
|
|
|
|
r.message = _("Impossibile avviare bastionguard-pacd (servizio utente)");
|
|
return r;
|
|
}
|
|
|
|
PacManager::Result PacManager::stop_pacd_user() {
|
|
Result r; r.backend = "user-service-manager";
|
|
|
|
if (!cmd_exists("/usr/libexec/bastionguard/bastionguard-service")) {
|
|
r.message = _("gestore servizi BastionGuard non disponibile");
|
|
return r;
|
|
}
|
|
|
|
// stop best-effort
|
|
run_user_servicectl({"disable", "--now", "BastionGuard-pacd.service"});
|
|
r.ok = true;
|
|
r.message = _("bastionguard-pacd fermato (servizio utente)");
|
|
return r;
|
|
}
|
|
|
|
|
|
PacManager::Result PacManager::enable_pac(const std::string& pac_url) {
|
|
auto r = enable_gnome(pac_url);
|
|
if (r.ok) return r;
|
|
|
|
r = enable_kde(pac_url);
|
|
if (r.ok) return r;
|
|
|
|
r = enable_xfce(pac_url);
|
|
if (r.ok) return r;
|
|
|
|
// headless fallback (NON PAC)
|
|
r = enable_env_fallback();
|
|
return r;
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_pac() {
|
|
auto r = disable_gnome();
|
|
if (r.ok) return r;
|
|
|
|
r = disable_kde();
|
|
if (r.ok) return r;
|
|
|
|
r = disable_xfce();
|
|
if (r.ok) return r;
|
|
|
|
r = disable_env_fallback();
|
|
return r;
|
|
}
|
|
|
|
PacManager::Result PacManager::enable_gnome(const std::string& pac_url) {
|
|
Result r; r.backend = "gnome";
|
|
|
|
if (!cmd_exists("gsettings")) {
|
|
r.message = _("gsettings non disponibile");
|
|
return r;
|
|
}
|
|
|
|
// Imposta PAC (AUTO)
|
|
int rc1 = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "mode", "auto"}).exit_code;
|
|
int rc2 = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "autoconfig-url", pac_url}).exit_code;
|
|
|
|
if (rc1 == 0 && rc2 == 0) {
|
|
r.ok = true;
|
|
r.message = _("Proxy GNOME impostato su AUTO (PAC)");
|
|
return r;
|
|
}
|
|
|
|
r.message = _("Impossibile impostare proxy GNOME via gsettings");
|
|
return r;
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_gnome() {
|
|
Result r; r.backend = "gnome";
|
|
|
|
if (!cmd_exists("gsettings")) {
|
|
r.message = _("gsettings non disponibile");
|
|
return r;
|
|
}
|
|
|
|
int rc = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "mode", "none"}).exit_code;
|
|
if (rc == 0) {
|
|
r.ok = true;
|
|
r.message = _("Proxy GNOME ripristinato a NONE");
|
|
return r;
|
|
}
|
|
r.message = _("Impossibile disabilitare proxy GNOME");
|
|
return r;
|
|
}
|
|
|
|
|
|
static fs::path kde_kioslaverc() {
|
|
return fs::path(Glib::get_home_dir()) / ".config" / "kioslaverc";
|
|
}
|
|
|
|
PacManager::Result PacManager::enable_kde(const std::string& pac_url) {
|
|
Result r; r.backend = "kde";
|
|
|
|
fs::path p = kde_kioslaverc();
|
|
try {
|
|
fs::create_directories(p.parent_path());
|
|
} catch (...) {}
|
|
|
|
if (cmd_exists("kwriteconfig6")) {
|
|
auto first = bg_process::run({"kwriteconfig6", "--file", p.string(),
|
|
"--group", "Proxy Settings", "--key", "ProxyType", "2"});
|
|
if (first.ok() && bg_process::run({"kwriteconfig6", "--file", p.string(),
|
|
"--group", "Proxy Settings", "--key", "AutoConfigScript", pac_url}).ok()) {
|
|
r.ok = true;
|
|
r.message = _("Proxy KDE impostato su PAC (kioslaverc)");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
try {
|
|
std::string content;
|
|
if (fs::exists(p)) {
|
|
std::ifstream in(p);
|
|
std::stringstream ss;
|
|
ss << in.rdbuf();
|
|
content = ss.str();
|
|
}
|
|
auto pos = content.find("[Proxy Settings]");
|
|
if (pos != std::string::npos) {
|
|
auto next = content.find("\n[", pos + 1);
|
|
if (next == std::string::npos) content.erase(pos);
|
|
else content.erase(pos, next - pos);
|
|
}
|
|
|
|
std::ofstream out(p, std::ios::app);
|
|
out << "\n[Proxy Settings]\n";
|
|
out << "ProxyType=2\n";
|
|
out << "AutoConfigScript=" << pac_url << "\n";
|
|
out.close();
|
|
|
|
r.ok = true;
|
|
r.message = _("Proxy KDE impostato su PAC (fallback write kioslaverc)");
|
|
return r;
|
|
} catch (...) {
|
|
r.message = _("Errore scrittura kioslaverc");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_kde() {
|
|
Result r; r.backend = "kde";
|
|
|
|
fs::path p = kde_kioslaverc();
|
|
if (!fs::exists(p)) {
|
|
r.message = _("kioslaverc non esiste");
|
|
return r;
|
|
}
|
|
|
|
if (cmd_exists("kwriteconfig6")) {
|
|
if (bg_process::run({"kwriteconfig6", "--file", p.string(),
|
|
"--group", "Proxy Settings", "--key", "ProxyType", "0"}).ok()) {
|
|
r.ok = true;
|
|
r.message = _("Proxy KDE ripristinato a NONE");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
try {
|
|
std::string content;
|
|
{
|
|
std::ifstream in(p);
|
|
std::stringstream ss;
|
|
ss << in.rdbuf();
|
|
content = ss.str();
|
|
}
|
|
|
|
auto tpos = content.find("ProxyType=");
|
|
if (tpos != std::string::npos) {
|
|
auto eol = content.find('\n', tpos);
|
|
content.replace(tpos, (eol == std::string::npos ? content.size()-tpos : eol-tpos),
|
|
"ProxyType=0");
|
|
} else {
|
|
content += "\n[Proxy Settings]\nProxyType=0\n";
|
|
}
|
|
|
|
std::ofstream out(p, std::ios::trunc);
|
|
out << content;
|
|
out.close();
|
|
|
|
r.ok = true;
|
|
r.message = _("Proxy KDE ripristinato a NONE (fallback)");
|
|
return r;
|
|
} catch (...) {
|
|
r.message = _("Errore scrittura kioslaverc");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
PacManager::Result PacManager::enable_xfce(const std::string& pac_url) {
|
|
Result r; r.backend = "xfce";
|
|
|
|
if (!cmd_exists("xfconf-query")) {
|
|
r.message = "xfconf-query non disponibile";
|
|
return r;
|
|
}
|
|
|
|
const int rc1 = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager",
|
|
"-p", "/proxy/mode", "-s", "2"}).exit_code;
|
|
const int rc2 = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager",
|
|
"-p", "/proxy/autoconfig-url", "-s", pac_url}).exit_code;
|
|
|
|
if (rc1 == 0 && rc2 == 0) {
|
|
r.ok = true;
|
|
r.message = _("Proxy XFCE impostato su AUTO (PAC)");
|
|
return r;
|
|
}
|
|
|
|
r.message = _("Impossibile impostare proxy XFCE (canale/proprietà potrebbero differire)");
|
|
return r;
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_xfce() {
|
|
Result r; r.backend = "xfce";
|
|
|
|
if (!cmd_exists("xfconf-query")) {
|
|
r.message = "xfconf-query non disponibile";
|
|
return r;
|
|
}
|
|
|
|
int rc = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager", "-p", "/proxy/mode", "-s", "0"}).exit_code;
|
|
if (rc == 0) {
|
|
r.ok = true;
|
|
r.message = _("Proxy XFCE ripristinato a NONE");
|
|
return r;
|
|
}
|
|
|
|
r.message = _("Impossibile disabilitare proxy XFCE");
|
|
return r;
|
|
}
|
|
|
|
|
|
static fs::path envd_file() {
|
|
return fs::path(Glib::get_home_dir()) / ".config" / "environment.d" / "90-bastionguard-proxy.conf";
|
|
}
|
|
|
|
PacManager::Result PacManager::enable_env_fallback() {
|
|
Result r; r.backend = "env";
|
|
try {
|
|
fs::path f = envd_file();
|
|
fs::create_directories(f.parent_path());
|
|
|
|
// Proxy locale (adattalo alla tua porta reale)
|
|
std::ofstream out(f, std::ios::trunc);
|
|
out << "http_proxy=http://127.0.0.1:3129\n";
|
|
out << "https_proxy=http://127.0.0.1:3129\n";
|
|
out << "HTTP_PROXY=http://127.0.0.1:3129\n";
|
|
out << "HTTPS_PROXY=http://127.0.0.1:3129\n";
|
|
out.close();
|
|
|
|
r.ok = true;
|
|
r.message = _("Fallback headless: environment.d impostato (richiede relogin/riavvio sessione)");
|
|
return r;
|
|
} catch (...) {
|
|
r.message = _("Impossibile scrivere environment.d fallback");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_env_fallback() {
|
|
Result r; r.backend = "env";
|
|
try {
|
|
fs::path f = envd_file();
|
|
if (fs::exists(f)) fs::remove(f);
|
|
r.ok = true;
|
|
r.message = _("Fallback headless: environment.d rimosso");
|
|
return r;
|
|
} catch (...) {
|
|
r.message = _("Impossibile rimuovere environment.d fallback");
|
|
return r;
|
|
}
|
|
}
|
|
|
|
PacManager::Result PacManager::enable_pac_with_pacd(const std::string& pac_url) {
|
|
auto s = start_pacd_user();
|
|
if (!s.ok) return s;
|
|
|
|
return enable_pac(pac_url);
|
|
}
|
|
|
|
PacManager::Result PacManager::disable_pac_with_pacd() {
|
|
auto d = disable_pac();
|
|
|
|
stop_pacd_user();
|
|
|
|
return d;
|
|
}
|