/* * Copyright (c) 2022, Ashley N. * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #include "EscalatorWindow.h" #include #include #include #include #include #include #include #include #include #include EscalatorWindow::EscalatorWindow(StringView executable, Vector arguments, EscalatorWindow::Options const& options) : m_arguments(arguments) , m_executable(executable) , m_current_user(options.current_user) , m_preserve_env(options.preserve_env) { auto app_icon = GUI::FileIconProvider::icon_for_executable(m_executable); set_title("Run as Root"); set_icon(app_icon.bitmap_for_size(16)); resize(345, 100); set_resizable(false); set_minimizable(false); auto main_widget = set_main_widget().release_value_but_fixme_should_propagate_errors(); main_widget->load_from_gml(escalator_gml).release_value_but_fixme_should_propagate_errors(); RefPtr app_label = *main_widget->find_descendant_of_type_named("description"); String prompt; if (options.description.is_empty()) prompt = String::formatted("{} requires root access. Please enter password for user \"{}\".", m_arguments[0], m_current_user.username()).release_value_but_fixme_should_propagate_errors(); else prompt = String::from_utf8(options.description).release_value_but_fixme_should_propagate_errors(); app_label->set_text(move(prompt)); m_icon_image_widget = *main_widget->find_descendant_of_type_named("icon"); m_icon_image_widget->set_bitmap(app_icon.bitmap_for_size(32)); m_ok_button = *main_widget->find_descendant_of_type_named("ok_button"); m_ok_button->on_click = [this](auto) { auto result = check_password(); if (result.is_error()) { GUI::MessageBox::show_error(this, DeprecatedString::formatted("Failed to execute command: {}", result.error())); close(); } }; m_ok_button->set_default(true); m_cancel_button = *main_widget->find_descendant_of_type_named("cancel_button"); m_cancel_button->on_click = [this](auto) { close(); }; m_password_input = *main_widget->find_descendant_of_type_named("password"); } ErrorOr EscalatorWindow::check_password() { DeprecatedString password = m_password_input->text(); if (password.is_empty()) { GUI::MessageBox::show_error(this, "Please enter a password."sv); return {}; } // FIXME: PasswordBox really should store its input directly as a SecretString. Core::SecretString password_secret = Core::SecretString::take_ownership(password.to_byte_buffer()); if (!m_current_user.authenticate(password_secret)) { GUI::MessageBox::show_error(this, "Incorrect or disabled password."sv); m_password_input->select_all(); return {}; } // Caller will close Escalator if error is returned. TRY(execute_command()); VERIFY_NOT_REACHED(); } ErrorOr EscalatorWindow::execute_command() { // Translate environ to format for Core::System::exec. Vector exec_environment; for (size_t i = 0; environ[i]; ++i) { StringView env_view { environ[i], strlen(environ[i]) }; auto maybe_needle = env_view.find('='); if (!maybe_needle.has_value()) continue; if (!m_preserve_env && env_view.substring_view(0, maybe_needle.value()) != "TERM"sv) continue; exec_environment.append(env_view); } // Escalate process privilege to root user. TRY(Core::System::seteuid(0)); auto root_user = TRY(Core::Account::from_uid(0)); TRY(root_user.login()); TRY(Core::System::pledge("stdio sendfd rpath exec")); TRY(Core::System::exec(m_executable, m_arguments, Core::System::SearchInPath::No, exec_environment)); VERIFY_NOT_REACHED(); }