Skip to content
API Documentation
BastionGuard™
BastionGuard::RootGuard::Client Class Reference

#include <RootGuardClient.hpp>

Classes

struct  Request

Public Member Functions

 Client ()
 ~Client ()
 Client (const Client &)=delete
Client & operator= (const Client &)=delete
sigc::signal< void(const Snapshot &)> & signal_updated () noexcept
void refresh ()
void start_service ()
void stop_service ()
void reload_policy ()
void restart_service ()
void set_immediate_protection (bool enabled)
void restore_event (const Event &event)
void remove_event (const Event &event)
void save_application_rules (ApplicationRules rules)

Private Types

enum class  Action {
  Refresh , Start , Stop , Reload ,
  Restart , SetProtection , Restore , Remove ,
  SaveApplicationRules , Quit
}

Private Member Functions

void enqueue (Request request)
void worker_loop ()
void on_dispatch ()
Snapshot collect_snapshot (const std::string &operation_message, bool operation_success) const
bool run_request (const Request &request, std::string &message) const

Private Attributes

Glib::Dispatcher dispatcher_
sigc::signal< void(const Snapshot &)> signal_updated_
std::mutex mutex_
std::condition_variable condition_
std::deque< Request > requests_
Snapshot pending_snapshot_
bool snapshot_ready_ {}
bool stopping_ {}
std::thread worker_

Detailed Description

Definition at line 51 of file RootGuardClient.hpp.

Member Enumeration Documentation

◆ Action

enum class BastionGuard::RootGuard::Client::Action
strongprivate
Enumerator
Refresh 
Start 
Stop 
Reload 
Restart 
SetProtection 
Restore 
Remove 
SaveApplicationRules 
Quit 

Definition at line 72 of file RootGuardClient.hpp.

72 {
73 Refresh,
74 Start,
75 Stop,
76 Reload,
77 Restart,
78 SetProtection,
79 Restore,
80 Remove,
81 SaveApplicationRules,
82 Quit,
83 };

Constructor & Destructor Documentation

◆ Client() [1/2]

BastionGuard::RootGuard::Client::Client ( )

Definition at line 298 of file RootGuardClient.cpp.

References dispatcher_, on_dispatch(), worker_, and worker_loop().

Referenced by Client(), and operator=().

◆ ~Client()

BastionGuard::RootGuard::Client::~Client ( )

Definition at line 304 of file RootGuardClient.cpp.

305{
306 {
307 std::lock_guard lock(mutex_);
308 stopping_ = true;
309 requests_.clear();
310 requests_.push_front(Request{Action::Quit, false, std::nullopt, {}});
311 }
312 condition_.notify_one();
313 if (worker_.joinable())
314 worker_.join();
315}
std::condition_variable condition_

References condition_, mutex_, Quit, requests_, stopping_, and worker_.

◆ Client() [2/2]

BastionGuard::RootGuard::Client::Client ( const Client & )
delete

References Client().

Member Function Documentation

◆ collect_snapshot()

Snapshot BastionGuard::RootGuard::Client::collect_snapshot ( const std::string & operation_message,
bool operation_success ) const
private

Definition at line 363 of file RootGuardClient.cpp.

365{
366 const CommandResult status_result = run_command({
368 });
369
370 Snapshot snapshot;
371 snapshot.service = parse_status(status_result.output);
372 snapshot.events = read_recent_events(400);
373 snapshot.application_rules = read_application_rules();
374 snapshot.operation_message = operation_message;
375 snapshot.operation_success = operation_success;
376 if (snapshot.service.state == "unknown" && status_result.exit_code != 0)
377 snapshot.service.state = "unavailable";
378 return snapshot;
379}
#define BASTIONGUARD_ROOTGUARD_SERVICE_HELPER
CommandResult run_command(const std::vector< std::string > &arguments)
std::vector< Event > read_recent_events(const std::size_t maximum)

References BASTIONGUARD_ROOTGUARD_SERVICE_HELPER, and BastionGuard::RootGuard::Snapshot::service.

Referenced by worker_loop().

◆ enqueue()

void BastionGuard::RootGuard::Client::enqueue ( Request request)
private

Definition at line 345 of file RootGuardClient.cpp.

346{
347 {
348 std::lock_guard lock(mutex_);
349 if (stopping_)
350 return;
351 if (request.action == Action::Refresh) {
352 const bool refreshAlreadyQueued = std::any_of(
353 requests_.begin(), requests_.end(),
354 [](const Request& queued) { return queued.action == Action::Refresh; });
355 if (refreshAlreadyQueued)
356 return;
357 }
358 requests_.push_back(std::move(request));
359 }
360 condition_.notify_one();
361}

References BastionGuard::RootGuard::Client::Request::action, condition_, mutex_, Refresh, requests_, and stopping_.

Referenced by refresh(), reload_policy(), remove_event(), restart_service(), restore_event(), save_application_rules(), set_immediate_protection(), start_service(), and stop_service().

◆ on_dispatch()

void BastionGuard::RootGuard::Client::on_dispatch ( )
private

Definition at line 537 of file RootGuardClient.cpp.

538{
539 Snapshot snapshot;
540 {
541 std::lock_guard lock(mutex_);
542 if (!snapshot_ready_)
543 return;
544 snapshot = std::move(pending_snapshot_);
545 snapshot_ready_ = false;
546 }
547 signal_updated_.emit(snapshot);
548}
sigc::signal< void(const Snapshot &)> signal_updated_

References mutex_, pending_snapshot_, signal_updated_, and snapshot_ready_.

Referenced by Client().

◆ operator=()

◆ refresh()

void BastionGuard::RootGuard::Client::refresh ( )

◆ reload_policy()

void BastionGuard::RootGuard::Client::reload_policy ( )

Definition at line 325 of file RootGuardClient.cpp.

References enqueue(), and Reload.

Referenced by operator=(), and RootGuardPage::RootGuardPage().

◆ remove_event()

void BastionGuard::RootGuard::Client::remove_event ( const Event & event)

Definition at line 335 of file RootGuardClient.cpp.

References enqueue(), and Remove.

Referenced by operator=(), and RootGuardPage::remove_event().

◆ restart_service()

void BastionGuard::RootGuard::Client::restart_service ( )

Definition at line 326 of file RootGuardClient.cpp.

References enqueue(), and Restart.

Referenced by operator=(), and RootGuardPage::RootGuardPage().

◆ restore_event()

void BastionGuard::RootGuard::Client::restore_event ( const Event & event)

Definition at line 331 of file RootGuardClient.cpp.

References enqueue(), and Restore.

Referenced by operator=(), and RootGuardPage::restore_event().

◆ run_request()

bool BastionGuard::RootGuard::Client::run_request ( const Request & request,
std::string & message ) const
private

Definition at line 381 of file RootGuardClient.cpp.

382{
383 if (request.action == Action::Refresh)
384 return true;
385
386 if (request.action == Action::Start || request.action == Action::Stop ||
387 request.action == Action::Reload || request.action == Action::Restart) {
388 const char* action = request.action == Action::Start ? "start" :
389 request.action == Action::Stop ? "stop" :
390 request.action == Action::Reload ? "reload" : "restart";
393 }), std::string("RootGuard action completed: ") + action, message);
394 }
395
396 if (request.action == Action::SetProtection) {
397 const auto result = run_command({
399 "set-protection", "--state", request.enabled ? "on" : "off"
400 });
401 if (!command_success(result, "RootGuard protection mode updated.", message))
402 return false;
403 const auto reload = run_command({
405 });
406 std::string reloadMessage;
407 const bool reloadSuccess = command_success(
408 reload, "RootGuard policy reloaded.", reloadMessage);
409 if (!reloadMessage.empty())
410 message += " " + reloadMessage;
411 if (!reloadSuccess && request.enabled) {
412 const auto rollback = run_command({
414 "set-protection", "--state", "off"
415 });
416 std::string rollbackMessage;
417 const bool rollbackSuccess = command_success(
418 rollback, "Unsafe future enablement was rolled back to audit mode.",
419 rollbackMessage);
420 message += rollbackSuccess
421 ? " " + rollbackMessage
422 : " WARNING: the policy rollback to audit mode failed: " + rollbackMessage;
423 }
424 return reloadSuccess;
425 }
426
427 if (request.action == Action::SaveApplicationRules) {
428 std::vector<std::string> command {
431 "set-application-rules"
432 };
433 const auto appendRules = [&command](const char* option,
434 const std::vector<std::string>& entries) {
435 for (const auto& entry : entries) {
436 command.emplace_back(option);
437 command.push_back(entry);
438 }
439 };
440 appendRules("--trusted-application",
441 request.application_rules.trustedApplications);
442 appendRules("--trusted-executable",
443 request.application_rules.trustedExecutables);
444 appendRules("--denied-executable",
445 request.application_rules.deniedExecutables);
446
447 const auto saveResult = run_command(command);
448 if (!command_success(saveResult,
449 "RootGuard application rules saved.", message))
450 return false;
451
452 const auto restartResult = run_command({
455 "restart"
456 });
457 std::string restartMessage;
458 const bool restartSuccess = command_success(
459 restartResult, "RootGuard restarted with the new rules.",
460 restartMessage);
461 if (!restartMessage.empty())
462 message += " " + restartMessage;
463 return restartSuccess;
464 }
465
466 if (!request.event)
467 return false;
468 const Event& event = *request.event;
469 if (event.filename.empty()) {
470 message = "The incident has no actionable path.";
471 return false;
472 }
473
474 if (request.action == Action::Restore) {
475 const bool metadataAvailable = event.old_mode != 0 || event.new_mode != 0 ||
476 event.old_uid != 0 || event.new_uid != 0 ||
477 event.old_gid != 0 || event.new_gid != 0;
478 if (!metadataAvailable) {
479 if (is_system_service_path(event.filename)) {
482 "unblock-service", "--path", event.filename
483 }), "The blocked service was unmasked. It was not restarted.", message);
484 }
485 message = "The change was denied before it was committed; no metadata restoration was required.";
486 return true;
487 }
490 "restore", "--path", event.filename,
491 "--mode", octal_argument(event.old_mode),
492 "--uid", std::to_string(event.old_uid),
493 "--gid", std::to_string(event.old_gid),
494 "--device", std::to_string(event.device),
495 "--inode", std::to_string(event.inode)
496 }), "Protected metadata restored.", message);
497 }
498
499 if (request.action == Action::Remove) {
502 "remove", "--path", event.filename,
503 "--device", std::to_string(event.device),
504 "--inode", std::to_string(event.inode)
505 }), "The file was removed and quarantined.", message);
506 }
507
508 return false;
509}
#define BASTIONGUARD_ROOTGUARD_ACTION_HELPER
#define BASTIONGUARD_PKEXEC
bool command_success(const CommandResult &result, const std::string &successFallback, std::string &message)
bool is_system_service_path(const std::string &path) noexcept

References BastionGuard::RootGuard::Client::Request::action, BastionGuard::RootGuard::Client::Request::application_rules, BASTIONGUARD_PKEXEC, BASTIONGUARD_ROOTGUARD_ACTION_HELPER, BASTIONGUARD_ROOTGUARD_SERVICE_HELPER, BastionGuard::RootGuard::ApplicationRules::deniedExecutables, BastionGuard::RootGuard::Client::Request::enabled, BastionGuard::RootGuard::Client::Request::event, BastionGuard::RootGuard::is_system_service_path(), Refresh, Reload, Remove, Restart, Restore, SaveApplicationRules, SetProtection, Start, Stop, BastionGuard::RootGuard::ApplicationRules::trustedApplications, and BastionGuard::RootGuard::ApplicationRules::trustedExecutables.

Referenced by worker_loop().

◆ save_application_rules()

void BastionGuard::RootGuard::Client::save_application_rules ( ApplicationRules rules)

Definition at line 339 of file RootGuardClient.cpp.

340{
341 enqueue(Request{Action::SaveApplicationRules, false, std::nullopt,
342 std::move(rules)});
343}

References enqueue(), and SaveApplicationRules.

Referenced by operator=(), and RootGuardPage::save_application_rules().

◆ set_immediate_protection()

void BastionGuard::RootGuard::Client::set_immediate_protection ( bool enabled)

Definition at line 327 of file RootGuardClient.cpp.

328{
329 enqueue(Request{Action::SetProtection, enabled, std::nullopt, {}});
330}

References enqueue(), and SetProtection.

Referenced by RootGuardPage::on_protection_toggled(), and operator=().

◆ signal_updated()

sigc::signal< void(const Snapshot &)> & BastionGuard::RootGuard::Client::signal_updated ( )
noexcept

Definition at line 317 of file RootGuardClient.cpp.

318{
319 return signal_updated_;
320}

References signal_updated_.

Referenced by operator=(), and RootGuardPage::RootGuardPage().

◆ start_service()

void BastionGuard::RootGuard::Client::start_service ( )

Definition at line 323 of file RootGuardClient.cpp.

323{ enqueue(Request{Action::Start, false, std::nullopt, {}}); }

References enqueue(), and Start.

Referenced by operator=(), and RootGuardPage::RootGuardPage().

◆ stop_service()

void BastionGuard::RootGuard::Client::stop_service ( )

Definition at line 324 of file RootGuardClient.cpp.

324{ enqueue(Request{Action::Stop, false, std::nullopt, {}}); }

References enqueue(), and Stop.

Referenced by operator=(), and RootGuardPage::RootGuardPage().

◆ worker_loop()

void BastionGuard::RootGuard::Client::worker_loop ( )
private

Definition at line 511 of file RootGuardClient.cpp.

512{
513 for (;;) {
514 Request request;
515 {
516 std::unique_lock lock(mutex_);
517 condition_.wait(lock, [this] { return !requests_.empty(); });
518 request = std::move(requests_.front());
519 requests_.pop_front();
520 }
521
522 if (request.action == Action::Quit)
523 break;
524
525 std::string message;
526 const bool success = run_request(request, message);
527 Snapshot snapshot = collect_snapshot(message, success);
528 {
529 std::lock_guard lock(mutex_);
530 pending_snapshot_ = std::move(snapshot);
531 snapshot_ready_ = true;
532 }
533 dispatcher_.emit();
534 }
535}
Snapshot collect_snapshot(const std::string &operation_message, bool operation_success) const
bool run_request(const Request &request, std::string &message) const

References BastionGuard::RootGuard::Client::Request::action, collect_snapshot(), condition_, dispatcher_, mutex_, pending_snapshot_, Quit, requests_, run_request(), and snapshot_ready_.

Referenced by Client().

Member Data Documentation

◆ condition_

std::condition_variable BastionGuard::RootGuard::Client::condition_
private

Definition at line 103 of file RootGuardClient.hpp.

Referenced by enqueue(), worker_loop(), and ~Client().

◆ dispatcher_

Glib::Dispatcher BastionGuard::RootGuard::Client::dispatcher_
private

Definition at line 99 of file RootGuardClient.hpp.

Referenced by Client(), and worker_loop().

◆ mutex_

std::mutex BastionGuard::RootGuard::Client::mutex_
mutableprivate

Definition at line 102 of file RootGuardClient.hpp.

Referenced by enqueue(), on_dispatch(), worker_loop(), and ~Client().

◆ pending_snapshot_

Snapshot BastionGuard::RootGuard::Client::pending_snapshot_
private

Definition at line 105 of file RootGuardClient.hpp.

Referenced by on_dispatch(), and worker_loop().

◆ requests_

std::deque<Request> BastionGuard::RootGuard::Client::requests_
private

Definition at line 104 of file RootGuardClient.hpp.

Referenced by enqueue(), worker_loop(), and ~Client().

◆ signal_updated_

sigc::signal<void(const Snapshot&)> BastionGuard::RootGuard::Client::signal_updated_
private

Definition at line 100 of file RootGuardClient.hpp.

Referenced by on_dispatch(), and signal_updated().

◆ snapshot_ready_

bool BastionGuard::RootGuard::Client::snapshot_ready_ {}
private

Definition at line 106 of file RootGuardClient.hpp.

Referenced by on_dispatch(), and worker_loop().

◆ stopping_

bool BastionGuard::RootGuard::Client::stopping_ {}
private

Definition at line 107 of file RootGuardClient.hpp.

Referenced by enqueue(), and ~Client().

◆ worker_

std::thread BastionGuard::RootGuard::Client::worker_
private

Definition at line 108 of file RootGuardClient.hpp.

Referenced by Client(), and ~Client().


The documentation for this class was generated from the following files: