From 24b1bdca27188377080b0ccb0c44988175669dd1 Mon Sep 17 00:00:00 2001 From: Fabian Dellwing Date: Thu, 27 Apr 2023 21:07:07 +0200 Subject: [PATCH] NetworkSettings: Use helper script to write config This change allows us to not run the app with elevated privileges. It uses the Escalator to call a helper and passes the settings as JsonObject to it. --- .../NetworkSettings/NetworkSettingsWidget.cpp | 84 ++++++++++++++----- .../NetworkSettings/NetworkSettingsWidget.h | 2 + .../Applications/NetworkSettings/main.cpp | 4 +- 3 files changed, 68 insertions(+), 22 deletions(-) diff --git a/Userland/Applications/NetworkSettings/NetworkSettingsWidget.cpp b/Userland/Applications/NetworkSettings/NetworkSettingsWidget.cpp index e8698e2d06a..4c22e047e40 100644 --- a/Userland/Applications/NetworkSettings/NetworkSettingsWidget.cpp +++ b/Userland/Applications/NetworkSettings/NetworkSettingsWidget.cpp @@ -1,16 +1,18 @@ /* * Copyright (c) 2022, Maciej + * Copyright (c) 2023, Fabian Dellwing * * SPDX-License-Identifier: BSD-2-Clause */ #include "NetworkSettingsWidget.h" - #include #include +#include #include #include #include +#include #include #include #include @@ -18,6 +20,7 @@ #include #include #include +#include namespace NetworkSettings { @@ -134,27 +137,68 @@ void NetworkSettingsWidget::on_switch_enabled_or_dhcp() void NetworkSettingsWidget::apply_settings() { - auto config_file = Core::ConfigFile::open_for_system("Network", Core::ConfigFile::AllowWriting::Yes).release_value_but_fixme_should_propagate_errors(); - for (auto const& adapter_data : m_network_adapters) { - auto netmask = IPv4Address::netmask_from_cidr(adapter_data.value.cidr).to_deprecated_string(); - config_file->write_bool_entry(adapter_data.key, "Enabled", adapter_data.value.enabled); - config_file->write_bool_entry(adapter_data.key, "DHCP", adapter_data.value.dhcp); - if (adapter_data.value.enabled && !adapter_data.value.dhcp) { - if (!IPv4Address::from_string(adapter_data.value.ip_address).has_value()) { - GUI::MessageBox::show_error(window(), DeprecatedString::formatted("Invalid IPv4 address for adapter {}", adapter_data.key)); - return; - } - if (!IPv4Address::from_string(adapter_data.value.default_gateway).has_value()) { - GUI::MessageBox::show_error(window(), DeprecatedString::formatted("Invalid IPv4 gateway for adapter {}", adapter_data.key)); - return; - } - } - config_file->write_entry(adapter_data.key, "IPv4Address", adapter_data.value.ip_address); - config_file->write_entry(adapter_data.key, "IPv4Netmask", netmask); - config_file->write_entry(adapter_data.key, "IPv4Gateway", adapter_data.value.default_gateway); + auto result = apply_settings_impl(); + if (result.is_error()) { + GUI::MessageBox::show_error(window(), result.release_error().string_literal()); + return; + } +} + +ErrorOr NetworkSettingsWidget::apply_settings_impl() +{ + auto maybe_json = TRY(create_settings_object()); + if (!maybe_json.has_value() || maybe_json.value().is_empty()) + return {}; + auto json = maybe_json.release_value(); + + auto pipefds = TRY(Core::System::pipe2(O_CLOEXEC)); + ScopeGuard guard_fd1 { [&] { close(pipefds[1]); } }; + { + posix_spawn_file_actions_t file_actions; + posix_spawn_file_actions_init(&file_actions); + posix_spawn_file_actions_adddup2(&file_actions, pipefds[0], STDIN_FILENO); + + ScopeGuard guard_fd0_and_file_actions { [&]() { + posix_spawn_file_actions_destroy(&file_actions); + close(pipefds[0]); + } }; + + char const* argv[] = { "/bin/Escalator", "-I", "-P", "To apply these changes please enter your password:", "/bin/network-settings", nullptr }; + (void)TRY(Core::System::posix_spawn("/bin/Escalator"sv, &file_actions, nullptr, const_cast(argv), environ)); + + auto outfile = TRY(Core::File::adopt_fd(pipefds[1], Core::File::OpenMode::Write, Core::File::ShouldCloseFileDescriptor::No)); + TRY(outfile->write_until_depleted(json.serialized().bytes())); } - GUI::Process::spawn_or_show_error(window(), "/bin/NetworkServer"sv); + return {}; +} + +ErrorOr> NetworkSettingsWidget::create_settings_object() +{ + auto json = JsonObject(); + for (auto const& adapter_data : m_network_adapters) { + auto netmask = TRY(IPv4Address::netmask_from_cidr(adapter_data.value.cidr).to_string()); + if (adapter_data.value.enabled && !adapter_data.value.dhcp) { + if (!IPv4Address::from_string(adapter_data.value.ip_address).has_value()) { + GUI::MessageBox::show_error(window(), TRY(String::formatted("Invalid IPv4 address for adapter {}", adapter_data.key))); + return Optional {}; + } + if (!IPv4Address::from_string(adapter_data.value.default_gateway).has_value()) { + GUI::MessageBox::show_error(window(), TRY(String::formatted("Invalid IPv4 gateway for adapter {}", adapter_data.key))); + return Optional {}; + } + } + + auto adapter = JsonObject(); + adapter.set("Enabled", adapter_data.value.enabled); + adapter.set("DHCP", adapter_data.value.dhcp); + adapter.set("IPv4Address", adapter_data.value.ip_address); + adapter.set("IPv4Netmask", netmask.to_deprecated_string()); + adapter.set("IPv4Gateway", adapter_data.value.default_gateway); + json.set(adapter_data.key, move(adapter)); + } + + return json; } void NetworkSettingsWidget::switch_adapter(DeprecatedString const& adapter) diff --git a/Userland/Applications/NetworkSettings/NetworkSettingsWidget.h b/Userland/Applications/NetworkSettings/NetworkSettingsWidget.h index fb55b06ea52..18522cd0dd7 100644 --- a/Userland/Applications/NetworkSettings/NetworkSettingsWidget.h +++ b/Userland/Applications/NetworkSettings/NetworkSettingsWidget.h @@ -32,6 +32,8 @@ private: void on_switch_adapter(DeprecatedString const& adapter); void on_switch_enabled_or_dhcp(); + ErrorOr apply_settings_impl(); + ErrorOr> create_settings_object(); HashMap m_network_adapters; Vector m_adapter_names; diff --git a/Userland/Applications/NetworkSettings/main.cpp b/Userland/Applications/NetworkSettings/main.cpp index 692d8a6c611..11b9cbb277d 100644 --- a/Userland/Applications/NetworkSettings/main.cpp +++ b/Userland/Applications/NetworkSettings/main.cpp @@ -19,8 +19,8 @@ ErrorOr serenity_main(Main::Arguments args) { TRY(Core::System::pledge("stdio rpath wpath cpath recvfd sendfd unix proc exec")); - TRY(Core::System::unveil("/bin/NetworkServer", "x")); - TRY(Core::System::unveil("/etc/Network.ini", "rwc")); + TRY(Core::System::unveil("/bin/Escalator", "x")); + TRY(Core::System::unveil("/etc/Network.ini", "r")); TRY(Core::System::unveil("/sys/kernel/net/adapters", "r")); TRY(Core::System::unveil("/res", "r")); TRY(Core::System::unveil("/tmp/session/%sid/portal/clipboard", "rw"));