Skip to content
API Documentation
BastionGuard™
PacManager.cpp
Go to the documentation of this file.
1/*
2 * BastionGuard™
3 * Copyright (C) 2025–2026 Calogero Scarnà
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 *
17 * BastionGuard™ is a trademark of Calogero Scarnà.
18 * The BastionGuard™ name and branding are not licensed under the GPL.
19 */
20
21#include "PacManager.hpp"
22#include "../SafeProcess.hpp"
23#include <cstdlib>
24#include <unistd.h>
25#include <cstdio>
26#include <array>
27#include <filesystem>
28#include <fstream>
29#include <sstream>
30#include <glib/gi18n.h>
31#include <glibmm/miscutils.h>
32#include <glibmm/shell.h>
33
34namespace fs = std::filesystem;
35
36bool PacManager::cmd_exists(const std::string& cmd) {
37 if (cmd.empty()) return false;
38 if (cmd.find('/') != std::string::npos) return access(cmd.c_str(), X_OK) == 0;
39 const char* configured_path = std::getenv("PATH");
40 std::istringstream dirs(configured_path ? configured_path : "/usr/local/bin:/usr/bin:/bin");
41 std::string dir;
42 while (std::getline(dirs, dir, ':')) {
43 if (dir.empty()) dir = ".";
44 if (access((fs::path(dir) / cmd).c_str(), X_OK) == 0) return true;
45 }
46 return false;
47}
48
49static bool run_user_servicectl(const std::vector<std::string>& args) {
50 std::vector<std::string> command = {
51 "/usr/libexec/bastionguard/bastionguard-service", "--user"};
52 command.insert(command.end(), args.begin(), args.end());
53 return bg_process::run(command).ok();
54}
55
57 Result r; r.backend = "user-service-manager";
58
59 if (!cmd_exists("/usr/libexec/bastionguard/bastionguard-service")) {
60 r.message = _("gestore servizi BastionGuard non disponibile");
61 return r;
62 }
63
64 if (run_user_servicectl({"daemon-reload"}) &&
65 run_user_servicectl({"enable", "--now", "BastionGuard-pacd.service"})) {
66 r.ok = true;
67 r.message = _("bastionguard-pacd avviato (servizio utente)");
68 return r;
69 }
70
71 r.message = _("Impossibile avviare bastionguard-pacd (servizio utente)");
72 return r;
73}
74
76 Result r; r.backend = "user-service-manager";
77
78 if (!cmd_exists("/usr/libexec/bastionguard/bastionguard-service")) {
79 r.message = _("gestore servizi BastionGuard non disponibile");
80 return r;
81 }
82
83 // stop best-effort
84 run_user_servicectl({"disable", "--now", "BastionGuard-pacd.service"});
85 r.ok = true;
86 r.message = _("bastionguard-pacd fermato (servizio utente)");
87 return r;
88}
89
90
91PacManager::Result PacManager::enable_pac(const std::string& pac_url) {
92 auto r = enable_gnome(pac_url);
93 if (r.ok) return r;
94
95 r = enable_kde(pac_url);
96 if (r.ok) return r;
97
98 r = enable_xfce(pac_url);
99 if (r.ok) return r;
100
101 // headless fallback (NON PAC)
103 return r;
104}
105
107 auto r = disable_gnome();
108 if (r.ok) return r;
109
110 r = disable_kde();
111 if (r.ok) return r;
112
113 r = disable_xfce();
114 if (r.ok) return r;
115
117 return r;
118}
119
120PacManager::Result PacManager::enable_gnome(const std::string& pac_url) {
121 Result r; r.backend = "gnome";
122
123 if (!cmd_exists("gsettings")) {
124 r.message = _("gsettings non disponibile");
125 return r;
126 }
127
128 // Imposta PAC (AUTO)
129 int rc1 = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "mode", "auto"}).exit_code;
130 int rc2 = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "autoconfig-url", pac_url}).exit_code;
131
132 if (rc1 == 0 && rc2 == 0) {
133 r.ok = true;
134 r.message = _("Proxy GNOME impostato su AUTO (PAC)");
135 return r;
136 }
137
138 r.message = _("Impossibile impostare proxy GNOME via gsettings");
139 return r;
140}
141
143 Result r; r.backend = "gnome";
144
145 if (!cmd_exists("gsettings")) {
146 r.message = _("gsettings non disponibile");
147 return r;
148 }
149
150 int rc = bg_process::run({"gsettings", "set", "org.gnome.system.proxy", "mode", "none"}).exit_code;
151 if (rc == 0) {
152 r.ok = true;
153 r.message = _("Proxy GNOME ripristinato a NONE");
154 return r;
155 }
156 r.message = _("Impossibile disabilitare proxy GNOME");
157 return r;
158}
159
160
161static fs::path kde_kioslaverc() {
162 return fs::path(Glib::get_home_dir()) / ".config" / "kioslaverc";
163}
164
165PacManager::Result PacManager::enable_kde(const std::string& pac_url) {
166 Result r; r.backend = "kde";
167
168 fs::path p = kde_kioslaverc();
169 try {
170 fs::create_directories(p.parent_path());
171 } catch (...) {}
172
173 if (cmd_exists("kwriteconfig6")) {
174 auto first = bg_process::run({"kwriteconfig6", "--file", p.string(),
175 "--group", "Proxy Settings", "--key", "ProxyType", "2"});
176 if (first.ok() && bg_process::run({"kwriteconfig6", "--file", p.string(),
177 "--group", "Proxy Settings", "--key", "AutoConfigScript", pac_url}).ok()) {
178 r.ok = true;
179 r.message = _("Proxy KDE impostato su PAC (kioslaverc)");
180 return r;
181 }
182 }
183
184 try {
185 std::string content;
186 if (fs::exists(p)) {
187 std::ifstream in(p);
188 std::stringstream ss;
189 ss << in.rdbuf();
190 content = ss.str();
191 }
192 auto pos = content.find("[Proxy Settings]");
193 if (pos != std::string::npos) {
194 auto next = content.find("\n[", pos + 1);
195 if (next == std::string::npos) content.erase(pos);
196 else content.erase(pos, next - pos);
197 }
198
199 std::ofstream out(p, std::ios::app);
200 out << "\n[Proxy Settings]\n";
201 out << "ProxyType=2\n";
202 out << "AutoConfigScript=" << pac_url << "\n";
203 out.close();
204
205 r.ok = true;
206 r.message = _("Proxy KDE impostato su PAC (fallback write kioslaverc)");
207 return r;
208 } catch (...) {
209 r.message = _("Errore scrittura kioslaverc");
210 return r;
211 }
212}
213
215 Result r; r.backend = "kde";
216
217 fs::path p = kde_kioslaverc();
218 if (!fs::exists(p)) {
219 r.message = _("kioslaverc non esiste");
220 return r;
221 }
222
223 if (cmd_exists("kwriteconfig6")) {
224 if (bg_process::run({"kwriteconfig6", "--file", p.string(),
225 "--group", "Proxy Settings", "--key", "ProxyType", "0"}).ok()) {
226 r.ok = true;
227 r.message = _("Proxy KDE ripristinato a NONE");
228 return r;
229 }
230 }
231
232 try {
233 std::string content;
234 {
235 std::ifstream in(p);
236 std::stringstream ss;
237 ss << in.rdbuf();
238 content = ss.str();
239 }
240
241 auto tpos = content.find("ProxyType=");
242 if (tpos != std::string::npos) {
243 auto eol = content.find('\n', tpos);
244 content.replace(tpos, (eol == std::string::npos ? content.size()-tpos : eol-tpos),
245 "ProxyType=0");
246 } else {
247 content += "\n[Proxy Settings]\nProxyType=0\n";
248 }
249
250 std::ofstream out(p, std::ios::trunc);
251 out << content;
252 out.close();
253
254 r.ok = true;
255 r.message = _("Proxy KDE ripristinato a NONE (fallback)");
256 return r;
257 } catch (...) {
258 r.message = _("Errore scrittura kioslaverc");
259 return r;
260 }
261}
262
263
264
265PacManager::Result PacManager::enable_xfce(const std::string& pac_url) {
266 Result r; r.backend = "xfce";
267
268 if (!cmd_exists("xfconf-query")) {
269 r.message = "xfconf-query non disponibile";
270 return r;
271 }
272
273 const int rc1 = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager",
274 "-p", "/proxy/mode", "-s", "2"}).exit_code;
275 const int rc2 = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager",
276 "-p", "/proxy/autoconfig-url", "-s", pac_url}).exit_code;
277
278 if (rc1 == 0 && rc2 == 0) {
279 r.ok = true;
280 r.message = _("Proxy XFCE impostato su AUTO (PAC)");
281 return r;
282 }
283
284 r.message = _("Impossibile impostare proxy XFCE (canale/proprietà potrebbero differire)");
285 return r;
286}
287
289 Result r; r.backend = "xfce";
290
291 if (!cmd_exists("xfconf-query")) {
292 r.message = "xfconf-query non disponibile";
293 return r;
294 }
295
296 int rc = bg_process::run({"xfconf-query", "-c", "xfce4-settings-manager", "-p", "/proxy/mode", "-s", "0"}).exit_code;
297 if (rc == 0) {
298 r.ok = true;
299 r.message = _("Proxy XFCE ripristinato a NONE");
300 return r;
301 }
302
303 r.message = _("Impossibile disabilitare proxy XFCE");
304 return r;
305}
306
307
308static fs::path envd_file() {
309 return fs::path(Glib::get_home_dir()) / ".config" / "environment.d" / "90-bastionguard-proxy.conf";
310}
311
313 Result r; r.backend = "env";
314 try {
315 fs::path f = envd_file();
316 fs::create_directories(f.parent_path());
317
318 // Proxy locale (adattalo alla tua porta reale)
319 std::ofstream out(f, std::ios::trunc);
320 out << "http_proxy=http://127.0.0.1:3129\n";
321 out << "https_proxy=http://127.0.0.1:3129\n";
322 out << "HTTP_PROXY=http://127.0.0.1:3129\n";
323 out << "HTTPS_PROXY=http://127.0.0.1:3129\n";
324 out.close();
325
326 r.ok = true;
327 r.message = _("Fallback headless: environment.d impostato (richiede relogin/riavvio sessione)");
328 return r;
329 } catch (...) {
330 r.message = _("Impossibile scrivere environment.d fallback");
331 return r;
332 }
333}
334
336 Result r; r.backend = "env";
337 try {
338 fs::path f = envd_file();
339 if (fs::exists(f)) fs::remove(f);
340 r.ok = true;
341 r.message = _("Fallback headless: environment.d rimosso");
342 return r;
343 } catch (...) {
344 r.message = _("Impossibile rimuovere environment.d fallback");
345 return r;
346 }
347}
348
350 auto s = start_pacd_user();
351 if (!s.ok) return s;
352
353 return enable_pac(pac_url);
354}
355
357 auto d = disable_pac();
358
360
361 return d;
362}
#define _(s)
static fs::path kde_kioslaverc()
static fs::path envd_file()
static bool run_user_servicectl(const std::vector< std::string > &args)
static Result start_pacd_user()
static Result enable_xfce(const std::string &pac_url)
static Result disable_pac_with_pacd()
static Result disable_gnome()
static Result enable_pac_with_pacd(const std::string &pac_url)
static Result enable_gnome(const std::string &pac_url)
static Result disable_kde()
static Result disable_xfce()
static Result disable_pac()
static Result enable_pac(const std::string &pac_url)
static bool cmd_exists(const std::string &cmd)
static Result stop_pacd_user()
static Result enable_kde(const std::string &pac_url)
static Result enable_env_fallback()
static Result disable_env_fallback()
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={})