Skip to content
API Documentation
BastionGuard™
bg_process Namespace Reference

Classes

struct  Result

Functions

bool exists_on_path (const std::string &name)
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={})

Function Documentation

◆ exists_on_path()

bool bg_process::exists_on_path ( const std::string & name)
inline

Definition at line 30 of file SafeProcess.hpp.

30 {
31 if (name.empty() || name.find('/') != std::string::npos || name == "." || name == "..")
32 return false;
33 const char* path = std::getenv("PATH");
34 if (!path) return false;
35 const std::string dirs(path);
36 std::size_t start = 0;
37 do {
38 const auto end = dirs.find(':', start);
39 const std::string dir = dirs.substr(start, end == std::string::npos ? end : end - start);
40 // Empty PATH components mean current directory: not trustworthy for security checks.
41 if (!dir.empty()) {
42 const std::string file = dir + "/" + name;
43 struct stat st{};
44 if (::stat(file.c_str(), &st) == 0 && S_ISREG(st.st_mode) &&
45 ::access(file.c_str(), X_OK) == 0) return true;
46 }
47 if (end == std::string::npos) break;
48 start = end + 1;
49 } while (true);
50 return false;
51}

References exists_on_path().

Referenced by exists_on_path(), has_in_path(), isClamdInstalled(), FirewallDetector::isFirewalldPresent(), FirewallDetector::isUfwPresent(), and reexec_inside_bwrap_with_custom_dns().

◆ run()

Result bg_process::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 = {} )
inline

Definition at line 53 of file SafeProcess.hpp.

56 {},
57 const std::function<bool(const std::string&)>& on_line = {}) {
58 Result result;
59 if (args.empty() || args[0].empty()) return result;
60 for (const auto& arg : args) if (arg.find('\0') != std::string::npos) return result;
61
62 int fd[2];
63 if (::pipe(fd) != 0) return result;
64 posix_spawn_file_actions_t actions;
65 if (posix_spawn_file_actions_init(&actions) != 0) {
66 ::close(fd[0]); ::close(fd[1]); return result;
67 }
68 posix_spawn_file_actions_addclose(&actions, fd[0]);
69 posix_spawn_file_actions_adddup2(&actions, fd[1], STDOUT_FILENO);
70 if (merge_stderr) posix_spawn_file_actions_adddup2(&actions, fd[1], STDERR_FILENO);
71 posix_spawn_file_actions_addclose(&actions, fd[1]);
72
73 std::vector<char*> argv;
74 for (const auto& arg : args) argv.push_back(const_cast<char*>(arg.c_str()));
75 argv.push_back(nullptr);
76
77 // Apply only explicitly supplied overrides, without invoking /usr/bin/env or shell.
78 std::vector<std::string> env_storage;
79 std::vector<char*> envp;
80 if (!environment.empty()) {
81 for (char** p = environ; p && *p; ++p) {
82 const std::string item(*p);
83 const auto pos = item.find('=');
84 if (pos != std::string::npos && environment.find(item.substr(0, pos)) == environment.end())
85 env_storage.push_back(item);
86 }
87 for (const auto& [key, value] : environment) {
88 if (key.empty() || key.find('=') != std::string::npos || key.find('\0') != std::string::npos || value.find('\0') != std::string::npos) {
89 posix_spawn_file_actions_destroy(&actions);
90 ::close(fd[0]); ::close(fd[1]); return result;
91 }
92 env_storage.push_back(key + "=" + value);
93 }
94 for (auto& item : env_storage) envp.push_back(item.data());
95 envp.push_back(nullptr);
96 }
97
98 pid_t child = -1;
99 const int err = posix_spawnp(&child, args[0].c_str(), &actions, nullptr,
100 argv.data(), environment.empty() ? environ : envp.data());
101 posix_spawn_file_actions_destroy(&actions);
102 ::close(fd[1]);
103 if (err != 0) { ::close(fd[0]); return result; }
104 result.started = true;
105 char buf[4096];
106 std::string pending;
107 std::size_t total = 0;
108 bool stopped = false;
109 for (;;) {
110 const ssize_t n = ::read(fd[0], buf, sizeof(buf));
111 if (n < 0 && errno == EINTR) continue;
112 if (n <= 0) break;
113 total += static_cast<std::size_t>(n);
114 if (total > limit) { result.truncated = true; stopped = true; break; }
115 if (on_line) {
116 pending.append(buf, static_cast<std::size_t>(n));
117 std::size_t p;
118 while ((p = pending.find('\n')) != std::string::npos) {
119 std::string line = pending.substr(0, p + 1);
120 pending.erase(0, p + 1);
121 if (!on_line(line)) { stopped = true; break; }
122 }
123 if (stopped) break;
124 // Guard against never-ending lines.
125 if (pending.size() > 65536) { result.truncated = true; stopped = true; break; }
126 } else {
127 result.output.append(buf, static_cast<std::size_t>(n));
128 }
129 }
130 if (on_line && !stopped && !pending.empty()) on_line(pending);
131 if (stopped) ::kill(child, SIGTERM);
132 ::close(fd[0]);
133 int status = 0;
134 pid_t waited;
135 do { waited = ::waitpid(child, &status, 0); } while (waited == -1 && errno == EINTR);
136 if (waited == child) {
137 if (WIFEXITED(status)) result.exit_code = WEXITSTATUS(status);
138 else if (WIFSIGNALED(status)) result.exit_code = 128 + WTERMSIG(status);
139 }
140 if (stopped) result.truncated = true;
141 return result;
142}
char ** environ

References run().

Referenced by anonymous_namespace{SettingsPage.cpp}::atomic_install_with_pkexec(), SettingsPage::build_antiphish_tab(), SettingsPage::build_email_security_tab(), SettingsPage::build_options_tab(), SettingsPage::build_proxy_bypass_tab(), SettingsPage::build_secure_payments_tab(), SettingsPage::build_whitelist_tab(), CaInstaller::ca_fingerprint(), can_bind_privileged_ports(), check_service_active(), UpdatePage::checkServiceStatus(), clamdscan_running(), BastionGuard::wizard::WizardWindow::configure_browser_doh(), BastionGuard::wizard::WizardWindow::configure_dnsmasq(), copy_with_pkexec(), detect_desktop_user_logind(), detect_desktop_user_who(), detect_distro(), detect_webserver(), PacManager::disable_gnome(), PacManager::disable_kde(), PacManager::disable_xfce(), Backend::disableClamonacc(), PacManager::enable_gnome(), PacManager::enable_kde(), PacManager::enable_xfce(), Backend::enableClamonacc(), Backend::enablePhishAutoUpdate(), findClamonaccService(), Backend::getClamonaccLogs(), Backend::getOnAccessEvents(), BrowserProxy::install_ca_firefox_profile(), BrowserProxy::install_ca_nssdb(), anonymous_namespace{BastionGuard-mailproxy.cpp}::install_cert_in_thunderbird(), install_to_system_data(), installPackages(), PrivacyPage::is_daemon_active(), Backend::isAntiphishActive(), Backend::isAntiransomActive(), Backend::isClamonaccActive(), Backend::isPhishAutoUpdateEnabled(), Backend::isSambaScanRunning(), anonymous_namespace{SettingsPage.cpp}::isServiceActive(), main(), BrowserProxy::nss_contains_ca(), SettingsPage::onAntiphishToggled(), SettingsPage::onAntiransomToggled(), UpdatePage::onSaneAutoToggled(), UpdatePage::onServiceToggled(), UpdatePage::onUpdateClicked(), reload_clamav_service(), Backend::reload_dnsmasq(), BastionGuard::DnsmasqBackend::reload_dnsmasq(), anonymous_namespace{BankPage.cpp}::restart_cef_service_user(), restart_clamd(), restart_service(), run(), CaInstaller::run(), ProxyConfig::run(), anonymous_namespace{wizard_setup.cpp}::run_capture(), anonymous_namespace{SettingsPage.cpp}::run_cmd(), anonymous_namespace{wizard_setup.cpp}::run_cmd_capture(), BastionGuard::wizard::WizardWindow::run_enable_user_agents(), run_trigger_cmd(), run_user_servicectl(), SaneSecurityUpdater::runHeadless(), SettingsPage::saveScannerConfig(), Backend::scanSambaDir(), BastionGuard::wizard::setup_firewall_ports(), Backend::start_antiphish(), Backend::start_antiransom(), BastionGuard::wizard::WizardWindow::start_execution(), PrivacyPage::start_privacy_daemon(), Backend::stop_antiphish(), Backend::stop_antiransom(), update_ports_in_file(), update_webserver_ports(), Backend::updatePhishLists(), UpdatePage::updateSaneSecurity(), Backend::updateSanesecurityDB(), Backend::updateYaraRules(), and write_temp_script_and_elevate().