From d8c36ed4585d3595794f250487128c389e3a9c6a Mon Sep 17 00:00:00 2001 From: rmg-x Date: Fri, 4 Oct 2024 17:15:53 -0500 Subject: [PATCH] LibCore: Remove unused classes and headers --- .../Userland/Libraries/LibCore/BUILD.gn | 18 - Userland/Libraries/LibCore/Account.cpp | 383 ------------------ Userland/Libraries/LibCore/Account.h | 95 ----- Userland/Libraries/LibCore/CMakeLists.txt | 12 - Userland/Libraries/LibCore/Debounce.h | 29 -- .../Libraries/LibCore/FilePermissionsMask.cpp | 176 -------- .../Libraries/LibCore/FilePermissionsMask.h | 57 --- Userland/Libraries/LibCore/GetPassword.cpp | 45 -- Userland/Libraries/LibCore/GetPassword.h | 16 - Userland/Libraries/LibCore/Group.cpp | 187 --------- Userland/Libraries/LibCore/Group.h | 51 --- Userland/Libraries/LibCore/LockFile.cpp | 57 --- Userland/Libraries/LibCore/LockFile.h | 32 -- .../LibCore/ProcessStatisticsReader.cpp | 112 ----- .../LibCore/ProcessStatisticsReader.h | 84 ---- .../Libraries/LibCore/SOCKSProxyClient.cpp | 311 -------------- Userland/Libraries/LibCore/SOCKSProxyClient.h | 64 --- Userland/Libraries/LibCore/SecretString.cpp | 50 --- Userland/Libraries/LibCore/SecretString.h | 37 -- Userland/Libraries/LibCore/UmaskScope.h | 30 -- 20 files changed, 1846 deletions(-) delete mode 100644 Userland/Libraries/LibCore/Account.cpp delete mode 100644 Userland/Libraries/LibCore/Account.h delete mode 100644 Userland/Libraries/LibCore/Debounce.h delete mode 100644 Userland/Libraries/LibCore/FilePermissionsMask.cpp delete mode 100644 Userland/Libraries/LibCore/FilePermissionsMask.h delete mode 100644 Userland/Libraries/LibCore/GetPassword.cpp delete mode 100644 Userland/Libraries/LibCore/GetPassword.h delete mode 100644 Userland/Libraries/LibCore/Group.cpp delete mode 100644 Userland/Libraries/LibCore/Group.h delete mode 100644 Userland/Libraries/LibCore/LockFile.cpp delete mode 100644 Userland/Libraries/LibCore/LockFile.h delete mode 100644 Userland/Libraries/LibCore/ProcessStatisticsReader.cpp delete mode 100644 Userland/Libraries/LibCore/ProcessStatisticsReader.h delete mode 100644 Userland/Libraries/LibCore/SOCKSProxyClient.cpp delete mode 100644 Userland/Libraries/LibCore/SOCKSProxyClient.h delete mode 100644 Userland/Libraries/LibCore/SecretString.cpp delete mode 100644 Userland/Libraries/LibCore/SecretString.h delete mode 100644 Userland/Libraries/LibCore/UmaskScope.h diff --git a/Meta/gn/secondary/Userland/Libraries/LibCore/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibCore/BUILD.gn index 3ef73ac6380..4a1e4cd3d73 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibCore/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibCore/BUILD.gn @@ -44,7 +44,6 @@ source_set("sources") { "ConfigFile.h", "DateTime.cpp", "DateTime.h", - "Debounce.h", "DeferredInvocationContext.h", "ElapsedTimer.cpp", "ElapsedTimer.h", @@ -58,8 +57,6 @@ source_set("sources") { "EventLoopImplementationUnix.h", "EventReceiver.cpp", "EventReceiver.h", - "LockFile.cpp", - "LockFile.h", "MappedFile.cpp", "MappedFile.h", "MimeData.cpp", @@ -71,18 +68,12 @@ source_set("sources") { "Platform/ProcessStatistics.h", "Process.cpp", "Process.h", - "ProcessStatisticsReader.cpp", - "ProcessStatisticsReader.h", "Promise.h", "Proxy.h", "Resource.cpp", "Resource.h", "ResourceImplementation.cpp", "ResourceImplementationFile.cpp", - "SOCKSProxyClient.cpp", - "SOCKSProxyClient.h", - "SecretString.cpp", - "SecretString.h", "SessionManagement.cpp", "SessionManagement.h", "SharedCircularQueue.h", @@ -100,18 +91,9 @@ source_set("sources") { "Timer.h", "UDPServer.cpp", "UDPServer.h", - "UmaskScope.h", ] if (current_os != "android") { sources += [ - "Account.cpp", - "Account.h", - "FilePermissionsMask.cpp", - "FilePermissionsMask.h", - "GetPassword.cpp", - "GetPassword.h", - "Group.cpp", - "Group.h", "LocalServer.cpp", "LocalServer.h", ] diff --git a/Userland/Libraries/LibCore/Account.cpp b/Userland/Libraries/LibCore/Account.cpp deleted file mode 100644 index 40a9fccf468..00000000000 --- a/Userland/Libraries/LibCore/Account.cpp +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * Copyright (c) 2021-2022, Brian Gianforcaro - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_HAIKU) -# include -# include -#endif -#include -#include -#include -#include - -namespace Core { - -static ByteString get_salt() -{ - char random_data[12]; - fill_with_random({ random_data, sizeof(random_data) }); - - StringBuilder builder; - builder.append("$5$"sv); - - // FIXME: change to TRY() and make method fallible - auto salt_string = MUST(encode_base64({ random_data, sizeof(random_data) })); - builder.append(salt_string); - - return builder.to_byte_string(); -} - -static Vector get_extra_gids(passwd const& pwd) -{ - StringView username { pwd.pw_name, strlen(pwd.pw_name) }; - Vector extra_gids; - setgrent(); - for (auto* group = getgrent(); group; group = getgrent()) { - if (group->gr_gid == pwd.pw_gid) - continue; - for (size_t i = 0; group->gr_mem[i]; ++i) { - if (username == group->gr_mem[i]) { - extra_gids.append(group->gr_gid); - break; - } - } - } - endgrent(); - return extra_gids; -} - -ErrorOr Account::from_passwd(passwd const& pwd, spwd const& spwd) -{ - Account account(pwd, spwd, get_extra_gids(pwd)); - endpwent(); -#ifndef AK_OS_BSD_GENERIC - endspent(); -#endif - return account; -} - -ErrorOr Account::self([[maybe_unused]] Read options) -{ - Vector extra_gids = TRY(Core::System::getgroups()); - - auto pwd = TRY(Core::System::getpwuid(getuid())); - if (!pwd.has_value()) - return Error::from_string_literal("No such user"); - - spwd spwd = {}; -#ifndef AK_OS_BSD_GENERIC - if (options != Read::PasswdOnly) { - auto maybe_spwd = TRY(Core::System::getspnam({ pwd->pw_name, strlen(pwd->pw_name) })); - if (!maybe_spwd.has_value()) - return Error::from_string_literal("No shadow entry for user"); - spwd = maybe_spwd.release_value(); - } -#endif - - return Account(*pwd, spwd, extra_gids); -} - -ErrorOr Account::from_name(StringView username, [[maybe_unused]] Read options) -{ - auto pwd = TRY(Core::System::getpwnam(username)); - if (!pwd.has_value()) - return Error::from_string_literal("No such user"); - - spwd spwd = {}; -#ifndef AK_OS_BSD_GENERIC - if (options != Read::PasswdOnly) { - auto maybe_spwd = TRY(Core::System::getspnam({ pwd->pw_name, strlen(pwd->pw_name) })); - if (!maybe_spwd.has_value()) - return Error::from_string_literal("No shadow entry for user"); - spwd = maybe_spwd.release_value(); - } -#endif - return from_passwd(*pwd, spwd); -} - -ErrorOr Account::from_uid(uid_t uid, [[maybe_unused]] Read options) -{ - auto pwd = TRY(Core::System::getpwuid(uid)); - if (!pwd.has_value()) - return Error::from_string_literal("No such user"); - - spwd spwd = {}; -#ifndef AK_OS_BSD_GENERIC - if (options != Read::PasswdOnly) { - auto maybe_spwd = TRY(Core::System::getspnam({ pwd->pw_name, strlen(pwd->pw_name) })); - if (!maybe_spwd.has_value()) - return Error::from_string_literal("No shadow entry for user"); - spwd = maybe_spwd.release_value(); - } -#endif - return from_passwd(*pwd, spwd); -} - -ErrorOr> Account::all([[maybe_unused]] Read options) -{ - Vector accounts; - char buffer[1024] = { 0 }; - - ScopeGuard pwent_guard([] { endpwent(); }); - setpwent(); - - while (true) { - auto pwd = TRY(Core::System::getpwent({ buffer, sizeof(buffer) })); - if (!pwd.has_value()) - break; - - spwd spwd = {}; - -#ifndef AK_OS_BSD_GENERIC - ScopeGuard spent_guard([] { endspent(); }); - if (options != Read::PasswdOnly) { - auto maybe_spwd = TRY(Core::System::getspnam({ pwd->pw_name, strlen(pwd->pw_name) })); - if (!maybe_spwd.has_value()) - return Error::from_string_literal("No shadow entry for user"); - spwd = maybe_spwd.release_value(); - } -#endif - - accounts.append({ *pwd, spwd, get_extra_gids(*pwd) }); - } - - return accounts; -} - -bool Account::authenticate(SecretString const& password) const -{ - // If there was no shadow entry for this account, authentication always fails. - if (!m_password_hash.has_value()) - return false; - - // An empty passwd field indicates that no password is required to log in. - if (m_password_hash->is_empty()) - return true; - - // FIXME: Use crypt_r if it can be built in lagom. - auto const bytes = m_password_hash->characters(); - char* hash = crypt(password.characters(), bytes); - return hash != nullptr && AK::timing_safe_compare(hash, bytes, m_password_hash->length()); -} - -ErrorOr Account::login() const -{ - TRY(Core::System::setgroups(m_extra_gids)); - TRY(Core::System::setgid(m_gid)); - TRY(Core::System::setuid(m_uid)); - - return {}; -} - -void Account::set_password(SecretString const& password) -{ - m_password_hash = crypt(password.characters(), get_salt().characters()); -} - -void Account::set_password_enabled(bool enabled) -{ - auto flattened_password_hash = m_password_hash.value_or(ByteString::empty()); - if (enabled && !flattened_password_hash.is_empty() && flattened_password_hash[0] == '!') { - m_password_hash = flattened_password_hash.substring(1, flattened_password_hash.length() - 1); - } else if (!enabled && (flattened_password_hash.is_empty() || flattened_password_hash[0] != '!')) { - StringBuilder builder; - builder.append('!'); - builder.append(flattened_password_hash); - m_password_hash = builder.to_byte_string(); - } -} - -void Account::delete_password() -{ - m_password_hash = ByteString::empty(); -} - -Account::Account(passwd const& pwd, spwd const& spwd, Vector extra_gids) - : m_username(pwd.pw_name) - , m_password_hash(spwd.sp_pwdp ? Optional(spwd.sp_pwdp) : OptionalNone {}) - , m_uid(pwd.pw_uid) - , m_gid(pwd.pw_gid) - , m_gecos(pwd.pw_gecos) - , m_home_directory(pwd.pw_dir) - , m_shell(pwd.pw_shell) - , m_extra_gids(move(extra_gids)) -{ -} - -ErrorOr Account::generate_passwd_file() const -{ - StringBuilder builder; - char buffer[1024] = { 0 }; - - ScopeGuard pwent_guard([] { endpwent(); }); - setpwent(); - - while (true) { - auto pwd = TRY(Core::System::getpwent({ buffer, sizeof(buffer) })); - if (!pwd.has_value()) - break; - - if (pwd->pw_name == m_username) { - if (m_deleted) - continue; - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - m_username, - m_uid, m_gid, - m_gecos, - m_home_directory, - m_shell); - - } else { - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - pwd->pw_name, pwd->pw_uid, - pwd->pw_gid, pwd->pw_gecos, pwd->pw_dir, - pwd->pw_shell); - } - } - - return builder.to_byte_string(); -} - -ErrorOr Account::generate_group_file() const -{ - StringBuilder builder; - char buffer[1024] = { 0 }; - - ScopeGuard pwent_guard([] { endgrent(); }); - setgrent(); - - while (true) { - auto group = TRY(Core::System::getgrent(buffer)); - if (!group.has_value()) - break; - - auto should_be_present = !m_deleted && m_extra_gids.contains_slow(group->gr_gid); - - auto already_present = false; - Vector members; - for (size_t i = 0; group->gr_mem[i]; ++i) { - auto const* member = group->gr_mem[i]; - if (member == m_username) { - already_present = true; - if (!should_be_present) - continue; - } - members.append(member); - } - - if (should_be_present && !already_present) - members.append(m_username.characters()); - - builder.appendff("{}:{}:{}:{}\n", group->gr_name, group->gr_passwd, group->gr_gid, ByteString::join(","sv, members)); - } - - return builder.to_byte_string(); -} - -#ifndef AK_OS_BSD_GENERIC -ErrorOr Account::generate_shadow_file() const -{ - StringBuilder builder; - - setspent(); - - struct spwd* p; - errno = 0; - while ((p = getspent())) { - if (p->sp_namp == m_username) { - if (m_deleted) - continue; - builder.appendff("{}:{}", m_username, m_password_hash.value_or(ByteString::empty())); - } else - builder.appendff("{}:{}", p->sp_namp, p->sp_pwdp); - - builder.appendff(":{}:{}:{}:{}:{}:{}:{}\n", - (p->sp_lstchg == -1) ? "" : ByteString::formatted("{}", p->sp_lstchg), - (p->sp_min == -1) ? "" : ByteString::formatted("{}", p->sp_min), - (p->sp_max == -1) ? "" : ByteString::formatted("{}", p->sp_max), - (p->sp_warn == -1) ? "" : ByteString::formatted("{}", p->sp_warn), - (p->sp_inact == -1) ? "" : ByteString::formatted("{}", p->sp_inact), - (p->sp_expire == -1) ? "" : ByteString::formatted("{}", p->sp_expire), - (p->sp_flag == 0) ? "" : ByteString::formatted("{}", p->sp_flag)); - } - endspent(); - - if (errno) - return Error::from_errno(errno); - - return builder.to_byte_string(); -} -#endif - -ErrorOr Account::sync() -{ - Core::UmaskScope umask_scope(0777); - - auto new_passwd_file_content = TRY(generate_passwd_file()); - auto new_group_file_content = TRY(generate_group_file()); -#ifndef AK_OS_BSD_GENERIC - auto new_shadow_file_content = TRY(generate_shadow_file()); -#endif - - char new_passwd_file[] = "/etc/passwd.XXXXXX"; - char new_group_file[] = "/etc/group.XXXXXX"; -#ifndef AK_OS_BSD_GENERIC - char new_shadow_file[] = "/etc/shadow.XXXXXX"; -#endif - - { - auto new_passwd_fd = TRY(Core::System::mkstemp(new_passwd_file)); - ScopeGuard new_passwd_fd_guard = [new_passwd_fd] { close(new_passwd_fd); }; - TRY(Core::System::fchmod(new_passwd_fd, 0644)); - - auto new_group_fd = TRY(Core::System::mkstemp(new_group_file)); - ScopeGuard new_group_fd_guard = [new_group_fd] { close(new_group_fd); }; - TRY(Core::System::fchmod(new_group_fd, 0644)); - -#ifndef AK_OS_BSD_GENERIC - auto new_shadow_fd = TRY(Core::System::mkstemp(new_shadow_file)); - ScopeGuard new_shadow_fd_guard = [new_shadow_fd] { close(new_shadow_fd); }; - TRY(Core::System::fchmod(new_shadow_fd, 0600)); -#endif - - auto nwritten = TRY(Core::System::write(new_passwd_fd, new_passwd_file_content.bytes())); - VERIFY(static_cast(nwritten) == new_passwd_file_content.length()); - - nwritten = TRY(Core::System::write(new_group_fd, new_group_file_content.bytes())); - VERIFY(static_cast(nwritten) == new_group_file_content.length()); - -#ifndef AK_OS_BSD_GENERIC - nwritten = TRY(Core::System::write(new_shadow_fd, new_shadow_file_content.bytes())); - VERIFY(static_cast(nwritten) == new_shadow_file_content.length()); -#endif - } - - auto new_passwd_file_view = StringView { new_passwd_file, sizeof(new_passwd_file) }; - TRY(Core::System::rename(new_passwd_file_view, "/etc/passwd"sv)); - - auto new_group_file_view = StringView { new_group_file, sizeof(new_group_file) }; - TRY(Core::System::rename(new_group_file_view, "/etc/group"sv)); -#ifndef AK_OS_BSD_GENERIC - auto new_shadow_file_view = StringView { new_shadow_file, sizeof(new_shadow_file) }; - TRY(Core::System::rename(new_shadow_file_view, "/etc/shadow"sv)); -#endif - - return {}; -} - -} diff --git a/Userland/Libraries/LibCore/Account.h b/Userland/Libraries/LibCore/Account.h deleted file mode 100644 index b176a443819..00000000000 --- a/Userland/Libraries/LibCore/Account.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#ifndef AK_OS_BSD_GENERIC -# include -#endif -#include - -namespace Core { - -#ifdef AK_OS_BSD_GENERIC -struct spwd { - char* sp_namp; - char* sp_pwdp; -}; -#endif - -class Account { -public: - enum class Read { - All, - PasswdOnly - }; - - static ErrorOr self(Read options = Read::All); - static ErrorOr from_name(StringView username, Read options = Read::All); - static ErrorOr from_uid(uid_t uid, Read options = Read::All); - static ErrorOr> all(Read options = Read::All); - - bool authenticate(SecretString const& password) const; - ErrorOr login() const; - - ByteString username() const { return m_username; } - ByteString password_hash() const { return m_password_hash.value_or(ByteString::empty()); } - - // Setters only affect in-memory copy of password. - // You must call sync to apply changes. - void set_password(SecretString const& password); - void set_password_enabled(bool enabled); - void set_home_directory(StringView home_directory) { m_home_directory = home_directory; } - void set_uid(uid_t uid) { m_uid = uid; } - void set_gid(gid_t gid) { m_gid = gid; } - void set_shell(StringView shell) { m_shell = shell; } - void set_gecos(StringView gecos) { m_gecos = gecos; } - void set_deleted() { m_deleted = true; } - void set_extra_gids(Vector extra_gids) { m_extra_gids = move(extra_gids); } - void delete_password(); - - // A nonexistent password means that this account was missing from /etc/shadow. - // It's considered to have a password in that case, and authentication will always fail. - bool has_password() const { return !m_password_hash.has_value() || !m_password_hash->is_empty(); } - - uid_t uid() const { return m_uid; } - gid_t gid() const { return m_gid; } - ByteString const& gecos() const { return m_gecos; } - ByteString const& home_directory() const { return m_home_directory; } - ByteString const& shell() const { return m_shell; } - Vector const& extra_gids() const { return m_extra_gids; } - - ErrorOr sync(); - -private: - static ErrorOr from_passwd(passwd const&, spwd const&); - - Account(passwd const& pwd, spwd const& spwd, Vector extra_gids); - - ErrorOr generate_passwd_file() const; - ErrorOr generate_group_file() const; -#ifndef AK_OS_BSD_GENERIC - ErrorOr generate_shadow_file() const; -#endif - - ByteString m_username; - - Optional m_password_hash; - uid_t m_uid { 0 }; - gid_t m_gid { 0 }; - ByteString m_gecos; - ByteString m_home_directory; - ByteString m_shell; - Vector m_extra_gids; - bool m_deleted { false }; -}; - -} diff --git a/Userland/Libraries/LibCore/CMakeLists.txt b/Userland/Libraries/LibCore/CMakeLists.txt index c750b8ff13c..57b21a7fe02 100644 --- a/Userland/Libraries/LibCore/CMakeLists.txt +++ b/Userland/Libraries/LibCore/CMakeLists.txt @@ -31,33 +31,21 @@ set(SOURCES EventLoopImplementation.cpp EventLoopImplementationUnix.cpp EventReceiver.cpp - LockFile.cpp MappedFile.cpp MimeData.cpp Notifier.cpp Process.cpp - ProcessStatisticsReader.cpp Resource.cpp ResourceImplementation.cpp ResourceImplementationFile.cpp - SecretString.cpp SessionManagement.cpp Socket.cpp - SOCKSProxyClient.cpp SystemServerTakeover.cpp TCPServer.cpp ThreadEventQueue.cpp Timer.cpp UDPServer.cpp ) -if (NOT ANDROID AND NOT WIN32 AND NOT EMSCRIPTEN) - list(APPEND SOURCES - Account.cpp - FilePermissionsMask.cpp - GetPassword.cpp - Group.cpp - ) -endif() if (NOT WIN32 AND NOT EMSCRIPTEN) list(APPEND SOURCES LocalServer.cpp) endif() diff --git a/Userland/Libraries/LibCore/Debounce.h b/Userland/Libraries/LibCore/Debounce.h deleted file mode 100644 index 10b59efee33..00000000000 --- a/Userland/Libraries/LibCore/Debounce.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2022, MacDue - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Core { - -template -auto debounce(int timeout, TFunction function) -{ - RefPtr timer; - return [=](T... args) mutable { - auto apply_function = [=] { function(args...); }; - if (timer) { - timer->stop(); - timer->on_timeout = move(apply_function); - } else { - timer = Core::Timer::create_single_shot(timeout, move(apply_function)); - } - timer->start(); - }; -} - -} diff --git a/Userland/Libraries/LibCore/FilePermissionsMask.cpp b/Userland/Libraries/LibCore/FilePermissionsMask.cpp deleted file mode 100644 index c5e8d45fdf5..00000000000 --- a/Userland/Libraries/LibCore/FilePermissionsMask.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2021, Xavier Defrang - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include - -#include - -namespace Core { - -enum State { - Classes, - Mode -}; - -enum ClassFlag { - Other = 1, - Group = 2, - User = 4, - All = 7 -}; - -enum Operation { - Add, - Remove, - Assign, -}; - -ErrorOr FilePermissionsMask::parse(StringView string) -{ - return (!string.is_empty() && is_ascii_digit(string[0])) - ? from_numeric_notation(string) - : from_symbolic_notation(string); -} - -ErrorOr FilePermissionsMask::from_numeric_notation(StringView string) -{ - string = string.trim_whitespace(); - mode_t mode = AK::StringUtils::convert_to_uint_from_octal(string, TrimWhitespace::No).value_or(010000); - if (mode > 07777) - return Error::from_string_literal("invalid octal representation"); - - FilePermissionsMask mask; - mask.assign_permissions(mode); - - // For compatibility purposes, just clear the special mode bits if we explicitly passed a 4-character mode. - if (string.length() >= 4) - mask.remove_permissions(07000); - - return mask; -} - -ErrorOr FilePermissionsMask::from_symbolic_notation(StringView string) -{ - auto mask = FilePermissionsMask(); - - u8 state = State::Classes; - u8 classes = 0; - u8 operation = 0; - - for (auto ch : string) { - switch (state) { - case State::Classes: { - // zero or more [ugoa] terminated by one operator [+-=] - if (ch == 'u') - classes |= ClassFlag::User; - else if (ch == 'g') - classes |= ClassFlag::Group; - else if (ch == 'o') - classes |= ClassFlag::Other; - else if (ch == 'a') - classes = ClassFlag::All; - else { - if (ch == '+') - operation = Operation::Add; - else if (ch == '-') - operation = Operation::Remove; - else if (ch == '=') - operation = Operation::Assign; - else if (classes == 0) - return Error::from_string_literal("invalid class: expected 'u', 'g', 'o' or 'a'"); - else - return Error::from_string_literal("invalid operation: expected '+', '-' or '='"); - - // if an operation was specified without a class, assume all - if (classes == 0) - classes = ClassFlag::All; - - state = State::Mode; - } - - break; - } - - case State::Mode: { - // one or more [rwx] terminated by a comma - - // End of mode part, expect class next - if (ch == ',') { - state = State::Classes; - classes = operation = 0; - continue; - } - - mode_t write_bits = 0; - bool apply_to_directories_and_executables_only = false; - - switch (ch) { - case 'r': - write_bits = 4; - break; - case 'w': - write_bits = 2; - break; - case 'x': - write_bits = 1; - break; - case 'X': - write_bits = 1; - apply_to_directories_and_executables_only = true; - break; - default: - return Error::from_string_literal("invalid symbolic permission: expected 'r', 'w' or 'x'"); - } - - mode_t clear_bits = operation == Operation::Assign ? 7 : write_bits; - - FilePermissionsMask& edit_mask = apply_to_directories_and_executables_only ? mask.directory_or_executable_mask() : mask; - - // Update masks one class at a time in other, group, user order - for (auto cls = classes; cls != 0; cls >>= 1) { - if (cls & 1) { - if (operation == Operation::Add || operation == Operation::Assign) - edit_mask.add_permissions(write_bits); - if (operation == Operation::Remove || operation == Operation::Assign) - edit_mask.remove_permissions(clear_bits); - } - write_bits <<= 3; - clear_bits <<= 3; - } - - break; - } - - default: - VERIFY_NOT_REACHED(); - } - } - - return mask; -} - -FilePermissionsMask& FilePermissionsMask::assign_permissions(mode_t mode) -{ - m_write_mask = mode; - m_clear_mask = 0777; - return *this; -} - -FilePermissionsMask& FilePermissionsMask::add_permissions(mode_t mode) -{ - m_write_mask |= mode; - return *this; -} - -FilePermissionsMask& FilePermissionsMask::remove_permissions(mode_t mode) -{ - m_clear_mask |= mode; - return *this; -} - -} diff --git a/Userland/Libraries/LibCore/FilePermissionsMask.h b/Userland/Libraries/LibCore/FilePermissionsMask.h deleted file mode 100644 index 2b95070daa7..00000000000 --- a/Userland/Libraries/LibCore/FilePermissionsMask.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021, Xavier Defrang - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Core { - -class FilePermissionsMask { -public: - static ErrorOr parse(StringView string); - static ErrorOr from_numeric_notation(StringView string); - static ErrorOr from_symbolic_notation(StringView string); - - FilePermissionsMask() - : m_clear_mask(0) - , m_write_mask(0) - { - } - - FilePermissionsMask& assign_permissions(mode_t mode); - FilePermissionsMask& add_permissions(mode_t mode); - FilePermissionsMask& remove_permissions(mode_t mode); - - mode_t apply(mode_t mode) const - { - if (m_directory_or_executable_mask && (S_ISDIR(mode) || (mode & 0111) != 0)) - mode = m_directory_or_executable_mask->apply(mode); - - return m_write_mask | (mode & ~m_clear_mask); - } - mode_t clear_mask() const { return m_clear_mask; } - mode_t write_mask() const { return m_write_mask; } - - FilePermissionsMask& directory_or_executable_mask() - { - if (!m_directory_or_executable_mask) - m_directory_or_executable_mask = make(); - - return *m_directory_or_executable_mask; - } - -private: - mode_t m_clear_mask; // the bits that will be cleared - mode_t m_write_mask; // the bits that will be set - - // A separate mask, only for files that already have some executable bit set or directories. - OwnPtr m_directory_or_executable_mask; -}; - -} diff --git a/Userland/Libraries/LibCore/GetPassword.cpp b/Userland/Libraries/LibCore/GetPassword.cpp deleted file mode 100644 index 56d1433f1f0..00000000000 --- a/Userland/Libraries/LibCore/GetPassword.cpp +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * Copyright (c) 2021, Emanuele Torre - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include - -namespace Core { - -ErrorOr get_password(StringView prompt) -{ - TRY(Core::System::write(STDOUT_FILENO, prompt.bytes())); - - auto original = TRY(Core::System::tcgetattr(STDIN_FILENO)); - - termios no_echo = original; - no_echo.c_lflag &= ~ECHO; - TRY(Core::System::tcsetattr(STDIN_FILENO, TCSAFLUSH, no_echo)); - - char* password = nullptr; - size_t n = 0; - - auto line_length = getline(&password, &n, stdin); - auto saved_errno = errno; - - tcsetattr(STDIN_FILENO, TCSAFLUSH, &original); - putchar('\n'); - - if (line_length < 0) - return Error::from_errno(saved_errno); - - VERIFY(line_length != 0); - - // Remove trailing '\n' read by getline(). - password[line_length - 1] = '\0'; - - return TRY(SecretString::take_ownership(password, line_length)); -} -} diff --git a/Userland/Libraries/LibCore/GetPassword.h b/Userland/Libraries/LibCore/GetPassword.h deleted file mode 100644 index cdf703451ea..00000000000 --- a/Userland/Libraries/LibCore/GetPassword.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Core { - -ErrorOr get_password(StringView prompt = "Password: "sv); - -} diff --git a/Userland/Libraries/LibCore/Group.cpp b/Userland/Libraries/LibCore/Group.cpp deleted file mode 100644 index 7f1c07722a3..00000000000 --- a/Userland/Libraries/LibCore/Group.cpp +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (c) 2022, Kenneth Myhra - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Core { - -ErrorOr Group::generate_group_file() const -{ - StringBuilder builder; - char buffer[1024] = { 0 }; - - ScopeGuard grent_guard([] { endgrent(); }); - setgrent(); - - while (true) { - auto group = TRY(Core::System::getgrent({ buffer, sizeof(buffer) })); - if (!group.has_value()) - break; - - if (group->gr_name == m_name) - builder.appendff("{}:x:{}:{}\n", m_name, m_id, ByteString::join(',', m_members)); - else { - Vector members; - if (group->gr_mem) { - for (size_t i = 0; group->gr_mem[i]; ++i) - members.append(group->gr_mem[i]); - } - - builder.appendff("{}:x:{}:{}\n", group->gr_name, group->gr_gid, ByteString::join(',', members)); - } - } - - return builder.to_byte_string(); -} - -ErrorOr Group::sync() -{ - Core::UmaskScope umask_scope(0777); - - auto new_group_file_content = TRY(generate_group_file()); - - char new_group_file[] = "/etc/group.XXXXXX"; - auto new_group_file_view = StringView { new_group_file, sizeof(new_group_file) }; - - { - auto new_group_fd = TRY(Core::System::mkstemp(new_group_file)); - ScopeGuard new_group_fd_guard([new_group_fd] { close(new_group_fd); }); - TRY(Core::System::fchmod(new_group_fd, 0664)); - - auto nwritten = TRY(Core::System::write(new_group_fd, new_group_file_content.bytes())); - VERIFY(static_cast(nwritten) == new_group_file_content.length()); - } - - TRY(Core::System::rename(new_group_file_view, "/etc/group"sv)); - - return {}; -} - -#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) && !defined(AK_OS_HAIKU) -ErrorOr Group::add_group(Group& group) -{ - if (group.name().is_empty()) - return Error::from_string_literal("Group name can not be empty."); - - // A quick sanity check on group name - if (group.name().find_any_of("\\/!@#$%^&*()~+=`:\n"sv, ByteString::SearchDirection::Forward).has_value()) - return Error::from_string_literal("Group name has invalid characters."); - - // Disallow names starting with '_', '-' or other non-alpha characters. - if (group.name().starts_with('_') || group.name().starts_with('-') || !is_ascii_alpha(group.name().characters()[0])) - return Error::from_string_literal("Group name has invalid characters."); - - // Verify group name does not already exist - if (TRY(name_exists(group.name()))) - return Error::from_string_literal("Group name already exists."); - - // Sort out the group id for the group - if (group.id() > 0) { - if (TRY(id_exists(group.id()))) - return Error::from_string_literal("Group ID already exists."); - } else { - gid_t group_id = 100; - while (true) { - if (!TRY(id_exists(group_id))) - break; - group_id++; - } - group.set_group_id(group_id); - } - - auto gr = TRY(group.to_libc_group()); - - FILE* file = fopen("/etc/group", "a"); - if (!file) - return Error::from_errno(errno); - - ScopeGuard file_guard { [&] { - fclose(file); - } }; - - if (putgrent(&gr, file) < 0) - return Error::from_errno(errno); - - return {}; -} -#endif - -ErrorOr> Group::all() -{ - Vector groups; - char buffer[1024] = { 0 }; - - ScopeGuard grent_guard([] { endgrent(); }); - setgrent(); - - while (true) { - auto group = TRY(Core::System::getgrent({ buffer, sizeof(buffer) })); - if (!group.has_value()) - break; - - Vector members; - if (group->gr_mem) { - for (size_t i = 0; group->gr_mem[i]; ++i) - members.append(group->gr_mem[i]); - } - - groups.append({ group->gr_name, group->gr_gid, move(members) }); - } - - return groups; -} - -Group::Group(ByteString name, gid_t id, Vector members) - : m_name(move(name)) - , m_id(id) - , m_members(move(members)) -{ -} - -ErrorOr Group::name_exists(StringView name) -{ - return TRY(Core::System::getgrnam(name)).has_value(); -} - -ErrorOr Group::id_exists(gid_t id) -{ - return TRY(Core::System::getgrgid(id)).has_value(); -} - -// NOTE: struct group returned from this function cannot outlive an instance of Group. -ErrorOr Group::to_libc_group() -{ - struct group gr; - gr.gr_name = const_cast(m_name.characters()); - gr.gr_passwd = const_cast("x"); - gr.gr_gid = m_id; - gr.gr_mem = nullptr; - - // FIXME: A better solution would surely be not using a static here - // NOTE: This now means that there cannot be multiple struct groups at the same time, because only one gr.gr_mem can ever be valid at the same time. - // NOTE: Not using a static here would result in gr.gr_mem being freed up on exit from this function. - static Vector members; - members.clear_with_capacity(); - if (m_members.size() > 0) { - TRY(members.try_ensure_capacity(m_members.size() + 1)); - for (auto member : m_members) - members.unchecked_append(const_cast(member.characters())); - members.unchecked_append(nullptr); - - gr.gr_mem = const_cast(members.data()); - } - - return gr; -} - -} diff --git a/Userland/Libraries/LibCore/Group.h b/Userland/Libraries/LibCore/Group.h deleted file mode 100644 index 3a985247a4b..00000000000 --- a/Userland/Libraries/LibCore/Group.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022, Kenneth Myhra - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Core { - -class Group { -public: -#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_ANDROID) && !defined(AK_OS_HAIKU) - static ErrorOr add_group(Group& group); -#endif - - static ErrorOr> all(); - - Group() = default; - Group(ByteString name, gid_t id = 0, Vector members = {}); - - ~Group() = default; - - ByteString const& name() const { return m_name; } - void set_name(ByteString const& name) { m_name = name; } - - gid_t id() const { return m_id; } - void set_group_id(gid_t const id) { m_id = id; } - - Vector& members() { return m_members; } - - ErrorOr sync(); - -private: - static ErrorOr name_exists(StringView name); - static ErrorOr id_exists(gid_t id); - ErrorOr to_libc_group(); - - ErrorOr generate_group_file() const; - - ByteString m_name; - gid_t m_id { 0 }; - Vector m_members; -}; - -} diff --git a/Userland/Libraries/LibCore/LockFile.cpp b/Userland/Libraries/LibCore/LockFile.cpp deleted file mode 100644 index 3d91913b057..00000000000 --- a/Userland/Libraries/LibCore/LockFile.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2021, Peter Elliott - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include - -namespace Core { - -LockFile::LockFile(char const* filename, Type type) - : m_filename(filename) -{ - if (Core::Directory::create(LexicalPath(m_filename).parent(), Core::Directory::CreateDirectories::Yes).is_error()) - return; - - m_fd = open(filename, O_RDONLY | O_CREAT | O_CLOEXEC, 0666); - if (m_fd == -1) { - m_errno = errno; - return; - } - - if (flock(m_fd, LOCK_NB | ((type == Type::Exclusive) ? LOCK_EX : LOCK_SH)) == -1) { - m_errno = errno; - close(m_fd); - m_fd = -1; - } -} - -LockFile::~LockFile() -{ - release(); -} - -bool LockFile::is_held() const -{ - return m_fd != -1; -} - -void LockFile::release() -{ - if (m_fd == -1) - return; - - unlink(m_filename); - flock(m_fd, LOCK_NB | LOCK_UN); - close(m_fd); - - m_fd = -1; -} - -} diff --git a/Userland/Libraries/LibCore/LockFile.h b/Userland/Libraries/LibCore/LockFile.h deleted file mode 100644 index e246edda52d..00000000000 --- a/Userland/Libraries/LibCore/LockFile.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2021, Peter Elliott - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -namespace Core { - -class LockFile { -public: - enum class Type { - Exclusive, - Shared - }; - - LockFile(LockFile const& other) = delete; - LockFile(char const* filename, Type type = Type::Exclusive); - ~LockFile(); - - bool is_held() const; - int error_code() const { return m_errno; } - void release(); - -private: - int m_fd { -1 }; - int m_errno { 0 }; - char const* m_filename { nullptr }; -}; - -} diff --git a/Userland/Libraries/LibCore/ProcessStatisticsReader.cpp b/Userland/Libraries/LibCore/ProcessStatisticsReader.cpp deleted file mode 100644 index b59ca5bb9f5..00000000000 --- a/Userland/Libraries/LibCore/ProcessStatisticsReader.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include -#include -#include -#include - -namespace Core { - -HashMap ProcessStatisticsReader::s_usernames; - -ErrorOr ProcessStatisticsReader::get_all(SeekableStream& proc_all_file, bool include_usernames) -{ - TRY(proc_all_file.seek(0, SeekMode::SetPosition)); - - AllProcessesStatistics all_processes_statistics; - - auto file_contents = TRY(proc_all_file.read_until_eof()); - auto json_obj = TRY(JsonValue::from_string(file_contents)).as_object(); - json_obj.get_array("processes"sv)->for_each([&](auto& value) { - JsonObject const& process_object = value.as_object(); - Core::ProcessStatistics process; - - // kernel data first - process.pid = process_object.get_u32("pid"sv).value_or(0); - process.pgid = process_object.get_u32("pgid"sv).value_or(0); - process.pgp = process_object.get_u32("pgp"sv).value_or(0); - process.sid = process_object.get_u32("sid"sv).value_or(0); - process.uid = process_object.get_u32("uid"sv).value_or(0); - process.gid = process_object.get_u32("gid"sv).value_or(0); - process.ppid = process_object.get_u32("ppid"sv).value_or(0); - process.kernel = process_object.get_bool("kernel"sv).value_or(false); - process.name = process_object.get_byte_string("name"sv).value_or(""); - process.executable = process_object.get_byte_string("executable"sv).value_or(""); - process.tty = process_object.get_byte_string("tty"sv).value_or(""); - process.pledge = process_object.get_byte_string("pledge"sv).value_or(""); - process.veil = process_object.get_byte_string("veil"sv).value_or(""); - process.creation_time = UnixDateTime::from_nanoseconds_since_epoch(process_object.get_i64("creation_time"sv).value_or(0)); - process.amount_virtual = process_object.get_u32("amount_virtual"sv).value_or(0); - process.amount_resident = process_object.get_u32("amount_resident"sv).value_or(0); - process.amount_shared = process_object.get_u32("amount_shared"sv).value_or(0); - process.amount_dirty_private = process_object.get_u32("amount_dirty_private"sv).value_or(0); - process.amount_clean_inode = process_object.get_u32("amount_clean_inode"sv).value_or(0); - process.amount_purgeable_volatile = process_object.get_u32("amount_purgeable_volatile"sv).value_or(0); - process.amount_purgeable_nonvolatile = process_object.get_u32("amount_purgeable_nonvolatile"sv).value_or(0); - - auto& thread_array = process_object.get_array("threads"sv).value(); - process.threads.ensure_capacity(thread_array.size()); - thread_array.for_each([&](auto& value) { - auto& thread_object = value.as_object(); - Core::ThreadStatistics thread; - thread.tid = thread_object.get_u32("tid"sv).value_or(0); - thread.times_scheduled = thread_object.get_u32("times_scheduled"sv).value_or(0); - thread.name = thread_object.get_byte_string("name"sv).value_or(""); - thread.state = thread_object.get_byte_string("state"sv).value_or(""); - thread.time_user = thread_object.get_u64("time_user"sv).value_or(0); - thread.time_kernel = thread_object.get_u64("time_kernel"sv).value_or(0); - thread.cpu = thread_object.get_u32("cpu"sv).value_or(0); - thread.priority = thread_object.get_u32("priority"sv).value_or(0); - thread.syscall_count = thread_object.get_u32("syscall_count"sv).value_or(0); - thread.inode_faults = thread_object.get_u32("inode_faults"sv).value_or(0); - thread.zero_faults = thread_object.get_u32("zero_faults"sv).value_or(0); - thread.cow_faults = thread_object.get_u32("cow_faults"sv).value_or(0); - thread.unix_socket_read_bytes = thread_object.get_u64("unix_socket_read_bytes"sv).value_or(0); - thread.unix_socket_write_bytes = thread_object.get_u64("unix_socket_write_bytes"sv).value_or(0); - thread.ipv4_socket_read_bytes = thread_object.get_u64("ipv4_socket_read_bytes"sv).value_or(0); - thread.ipv4_socket_write_bytes = thread_object.get_u64("ipv4_socket_write_bytes"sv).value_or(0); - thread.file_read_bytes = thread_object.get_u64("file_read_bytes"sv).value_or(0); - thread.file_write_bytes = thread_object.get_u64("file_write_bytes"sv).value_or(0); - process.threads.append(move(thread)); - }); - - // and synthetic data last - if (include_usernames) { - process.username = username_from_uid(process.uid); - } - all_processes_statistics.processes.append(move(process)); - }); - - all_processes_statistics.total_time_scheduled = json_obj.get_u64("total_time"sv).value_or(0); - all_processes_statistics.total_time_scheduled_kernel = json_obj.get_u64("total_time_kernel"sv).value_or(0); - return all_processes_statistics; -} - -ErrorOr ProcessStatisticsReader::get_all(bool include_usernames) -{ - auto proc_all_file = TRY(Core::File::open("/sys/kernel/processes"sv, Core::File::OpenMode::Read)); - return get_all(*proc_all_file, include_usernames); -} - -ByteString ProcessStatisticsReader::username_from_uid(uid_t uid) -{ - if (s_usernames.is_empty()) { - setpwent(); - while (auto* passwd = getpwent()) - s_usernames.set(passwd->pw_uid, passwd->pw_name); - endpwent(); - } - - auto it = s_usernames.find(uid); - if (it != s_usernames.end()) - return (*it).value; - return ByteString::number(uid); -} -} diff --git a/Userland/Libraries/LibCore/ProcessStatisticsReader.h b/Userland/Libraries/LibCore/ProcessStatisticsReader.h deleted file mode 100644 index b49c3953afe..00000000000 --- a/Userland/Libraries/LibCore/ProcessStatisticsReader.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2018-2021, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include - -namespace Core { - -struct ThreadStatistics { - pid_t tid; - unsigned times_scheduled; - u64 time_user; - u64 time_kernel; - unsigned syscall_count; - unsigned inode_faults; - unsigned zero_faults; - unsigned cow_faults; - u64 unix_socket_read_bytes; - u64 unix_socket_write_bytes; - u64 ipv4_socket_read_bytes; - u64 ipv4_socket_write_bytes; - u64 file_read_bytes; - u64 file_write_bytes; - ByteString state; - u32 cpu; - u32 priority; - ByteString name; -}; - -struct ProcessStatistics { - // Keep this in sync with /sys/kernel/processes. - // From the kernel side: - pid_t pid; - pid_t pgid; - pid_t pgp; - pid_t sid; - uid_t uid; - gid_t gid; - pid_t ppid; - bool kernel; - ByteString name; - ByteString executable; - ByteString tty; - ByteString pledge; - ByteString veil; - UnixDateTime creation_time; - size_t amount_virtual; - size_t amount_resident; - size_t amount_shared; - size_t amount_dirty_private; - size_t amount_clean_inode; - size_t amount_purgeable_volatile; - size_t amount_purgeable_nonvolatile; - - Vector threads; - - // synthetic - ByteString username; -}; - -struct AllProcessesStatistics { - Vector processes; - u64 total_time_scheduled; - u64 total_time_scheduled_kernel; -}; - -class ProcessStatisticsReader { -public: - static ErrorOr get_all(SeekableStream&, bool include_usernames = true); - static ErrorOr get_all(bool include_usernames = true); - -private: - static ByteString username_from_uid(uid_t); - static HashMap s_usernames; -}; - -} diff --git a/Userland/Libraries/LibCore/SOCKSProxyClient.cpp b/Userland/Libraries/LibCore/SOCKSProxyClient.cpp deleted file mode 100644 index db738c47ba4..00000000000 --- a/Userland/Libraries/LibCore/SOCKSProxyClient.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (c) 2022, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -enum class Method : u8 { - NoAuth = 0x00, - GSSAPI = 0x01, - UsernamePassword = 0x02, - NoAcceptableMethods = 0xFF, -}; - -enum class AddressType : u8 { - IPV4 = 0x01, - DomainName = 0x03, - IPV6 = 0x04, -}; - -enum class Reply { - Succeeded = 0x00, - GeneralSocksServerFailure = 0x01, - ConnectionNotAllowedByRuleset = 0x02, - NetworkUnreachable = 0x03, - HostUnreachable = 0x04, - ConnectionRefused = 0x05, - TTLExpired = 0x06, - CommandNotSupported = 0x07, - AddressTypeNotSupported = 0x08, -}; - -struct [[gnu::packed]] Socks5VersionIdentifierAndMethodSelectionMessage { - u8 version_identifier; - u8 method_count; - // NOTE: We only send a single method, so we don't need to make this variable-length. - u8 methods[1]; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -struct [[gnu::packed]] Socks5InitialResponse { - u8 version_identifier; - u8 method; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -struct [[gnu::packed]] Socks5ConnectRequestHeader { - u8 version_identifier; - u8 command; - u8 reserved; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -struct [[gnu::packed]] Socks5ConnectRequestTrailer { - u16 port; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -struct [[gnu::packed]] Socks5ConnectResponseHeader { - u8 version_identifier; - u8 status; - u8 reserved; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -struct [[gnu::packed]] Socks5ConnectResponseTrailer { - u8 bind_port; -}; - -struct [[gnu::packed]] Socks5UsernamePasswordResponse { - u8 version_identifier; - u8 status; -}; - -template<> -struct AK::Traits : public AK::DefaultTraits { - static constexpr bool is_trivially_serializable() { return true; } -}; - -namespace { -StringView reply_response_name(Reply reply) -{ - switch (reply) { - case Reply::Succeeded: - return "Succeeded"sv; - case Reply::GeneralSocksServerFailure: - return "GeneralSocksServerFailure"sv; - case Reply::ConnectionNotAllowedByRuleset: - return "ConnectionNotAllowedByRuleset"sv; - case Reply::NetworkUnreachable: - return "NetworkUnreachable"sv; - case Reply::HostUnreachable: - return "HostUnreachable"sv; - case Reply::ConnectionRefused: - return "ConnectionRefused"sv; - case Reply::TTLExpired: - return "TTLExpired"sv; - case Reply::CommandNotSupported: - return "CommandNotSupported"sv; - case Reply::AddressTypeNotSupported: - return "AddressTypeNotSupported"sv; - } - VERIFY_NOT_REACHED(); -} - -ErrorOr send_version_identifier_and_method_selection_message(Core::Socket& socket, Core::SOCKSProxyClient::Version version, Method method) -{ - Socks5VersionIdentifierAndMethodSelectionMessage message { - .version_identifier = to_underlying(version), - .method_count = 1, - .methods = { to_underlying(method) }, - }; - TRY(socket.write_value(message)); - - auto response = TRY(socket.read_value()); - - if (response.version_identifier != to_underlying(version)) - return Error::from_string_literal("SOCKS negotiation failed: Invalid version identifier"); - - if (response.method != to_underlying(method)) - return Error::from_string_literal("SOCKS negotiation failed: Failed to negotiate a method"); - - return {}; -} - -ErrorOr send_connect_request_message(Core::Socket& socket, Core::SOCKSProxyClient::Version version, Core::SOCKSProxyClient::HostOrIPV4 target, int port, Core::SOCKSProxyClient::Command command) -{ - AllocatingMemoryStream stream; - - Socks5ConnectRequestHeader header { - .version_identifier = to_underlying(version), - .command = to_underlying(command), - .reserved = 0, - }; - Socks5ConnectRequestTrailer trailer { - .port = htons(port), - }; - - TRY(stream.write_value(header)); - - TRY(target.visit( - [&](ByteString const& hostname) -> ErrorOr { - u8 address_data[2]; - address_data[0] = to_underlying(AddressType::DomainName); - address_data[1] = hostname.length(); - TRY(stream.write_until_depleted({ address_data, sizeof(address_data) })); - TRY(stream.write_until_depleted({ hostname.characters(), hostname.length() })); - return {}; - }, - [&](u32 ipv4) -> ErrorOr { - u8 address_data[5]; - address_data[0] = to_underlying(AddressType::IPV4); - u32 network_ordered_ipv4 = NetworkOrdered(ipv4); - memcpy(address_data + 1, &network_ordered_ipv4, sizeof(network_ordered_ipv4)); - TRY(stream.write_until_depleted({ address_data, sizeof(address_data) })); - return {}; - })); - - TRY(stream.write_value(trailer)); - - auto buffer = TRY(ByteBuffer::create_uninitialized(stream.used_buffer_size())); - TRY(stream.read_until_filled(buffer.bytes())); - TRY(socket.write_until_depleted(buffer)); - - auto response_header = TRY(socket.read_value()); - - if (response_header.version_identifier != to_underlying(version)) - return Error::from_string_literal("SOCKS negotiation failed: Invalid version identifier"); - - auto response_address_type = TRY(socket.read_value()); - - switch (AddressType(response_address_type)) { - case AddressType::IPV4: { - u8 response_address_data[4]; - TRY(socket.read_until_filled({ response_address_data, sizeof(response_address_data) })); - break; - } - case AddressType::DomainName: { - auto response_address_length = TRY(socket.read_value()); - auto buffer = TRY(ByteBuffer::create_uninitialized(response_address_length)); - TRY(socket.read_until_filled(buffer)); - break; - } - case AddressType::IPV6: - default: - return Error::from_string_literal("SOCKS negotiation failed: Invalid connect response address type"); - } - - [[maybe_unused]] auto bound_port = TRY(socket.read_value()); - - return Reply(response_header.status); -} - -ErrorOr send_username_password_authentication_message(Core::Socket& socket, Core::SOCKSProxyClient::UsernamePasswordAuthenticationData const& auth_data) -{ - AllocatingMemoryStream stream; - - u8 version = 0x01; - TRY(stream.write_value(version)); - - u8 username_length = auth_data.username.length(); - TRY(stream.write_value(username_length)); - - TRY(stream.write_until_depleted({ auth_data.username.characters(), auth_data.username.length() })); - - u8 password_length = auth_data.password.length(); - TRY(stream.write_value(password_length)); - - TRY(stream.write_until_depleted({ auth_data.password.characters(), auth_data.password.length() })); - - auto buffer = TRY(ByteBuffer::create_uninitialized(stream.used_buffer_size())); - TRY(stream.read_until_filled(buffer.bytes())); - - TRY(socket.write_until_depleted(buffer)); - - auto response = TRY(socket.read_value()); - - if (response.version_identifier != version) - return Error::from_string_literal("SOCKS negotiation failed: Invalid version identifier"); - - return response.status; -} -} - -namespace Core { - -SOCKSProxyClient::~SOCKSProxyClient() -{ - close(); - m_socket.on_ready_to_read = nullptr; -} - -ErrorOr> SOCKSProxyClient::connect(Socket& underlying, Version version, HostOrIPV4 const& target, int target_port, Variant const& auth_data, Command command) -{ - if (version != Version::V5) - return Error::from_string_literal("SOCKS version not supported"); - - return auth_data.visit( - [&](Empty) -> ErrorOr> { - TRY(send_version_identifier_and_method_selection_message(underlying, version, Method::NoAuth)); - auto reply = TRY(send_connect_request_message(underlying, version, target, target_port, command)); - if (reply != Reply::Succeeded) { - underlying.close(); - return Error::from_string_view(reply_response_name(reply)); - } - - return adopt_nonnull_own_or_enomem(new SOCKSProxyClient { - underlying, - nullptr, - }); - }, - [&](UsernamePasswordAuthenticationData const& auth_data) -> ErrorOr> { - TRY(send_version_identifier_and_method_selection_message(underlying, version, Method::UsernamePassword)); - auto auth_response = TRY(send_username_password_authentication_message(underlying, auth_data)); - if (auth_response != 0) { - underlying.close(); - return Error::from_string_literal("SOCKS authentication failed"); - } - - auto reply = TRY(send_connect_request_message(underlying, version, target, target_port, command)); - if (reply != Reply::Succeeded) { - underlying.close(); - return Error::from_string_view(reply_response_name(reply)); - } - - return adopt_nonnull_own_or_enomem(new SOCKSProxyClient { - underlying, - nullptr, - }); - }); -} - -ErrorOr> SOCKSProxyClient::connect(HostOrIPV4 const& server, int server_port, Version version, HostOrIPV4 const& target, int target_port, Variant const& auth_data, Command command) -{ - auto underlying = TRY(server.visit( - [&](u32 ipv4) { - return Core::TCPSocket::connect({ IPv4Address(ipv4), static_cast(server_port) }); - }, - [&](ByteString const& hostname) { - return Core::TCPSocket::connect(hostname, static_cast(server_port)); - })); - - auto socket = TRY(connect(*underlying, version, target, target_port, auth_data, command)); - socket->m_own_underlying_socket = move(underlying); - dbgln("SOCKS proxy connected, have {} available bytes", TRY(socket->m_socket.pending_bytes())); - return socket; -} - -} diff --git a/Userland/Libraries/LibCore/SOCKSProxyClient.h b/Userland/Libraries/LibCore/SOCKSProxyClient.h deleted file mode 100644 index cbb816870df..00000000000 --- a/Userland/Libraries/LibCore/SOCKSProxyClient.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2022, Ali Mohammad Pur - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Core { -class SOCKSProxyClient final : public Socket { -public: - enum class Version : u8 { - V4 = 0x04, - V5 = 0x05, - }; - - struct UsernamePasswordAuthenticationData { - ByteString username; - ByteString password; - }; - - enum class Command : u8 { - Connect = 0x01, - Bind = 0x02, - UDPAssociate = 0x03, - }; - - using HostOrIPV4 = Variant; - - static ErrorOr> connect(Socket& underlying, Version, HostOrIPV4 const& target, int target_port, Variant const& auth_data = {}, Command = Command::Connect); - static ErrorOr> connect(HostOrIPV4 const& server, int server_port, Version, HostOrIPV4 const& target, int target_port, Variant const& auth_data = {}, Command = Command::Connect); - - virtual ~SOCKSProxyClient() override; - - // ^Stream::Stream - virtual ErrorOr read_some(Bytes bytes) override { return m_socket.read_some(bytes); } - virtual ErrorOr write_some(ReadonlyBytes bytes) override { return m_socket.write_some(bytes); } - virtual bool is_eof() const override { return m_socket.is_eof(); } - virtual bool is_open() const override { return m_socket.is_open(); } - virtual void close() override { m_socket.close(); } - - // ^Stream::Socket - virtual ErrorOr pending_bytes() const override { return m_socket.pending_bytes(); } - virtual ErrorOr can_read_without_blocking(int timeout = 0) const override { return m_socket.can_read_without_blocking(timeout); } - virtual ErrorOr set_blocking(bool enabled) override { return m_socket.set_blocking(enabled); } - virtual ErrorOr set_close_on_exec(bool enabled) override { return m_socket.set_close_on_exec(enabled); } - virtual void set_notifications_enabled(bool enabled) override { m_socket.set_notifications_enabled(enabled); } - -private: - SOCKSProxyClient(Socket& socket, OwnPtr own_socket) - : m_socket(socket) - , m_own_underlying_socket(move(own_socket)) - { - m_socket.on_ready_to_read = [this] { on_ready_to_read(); }; - } - - Socket& m_socket; - OwnPtr m_own_underlying_socket; -}; -} diff --git a/Userland/Libraries/LibCore/SecretString.cpp b/Userland/Libraries/LibCore/SecretString.cpp deleted file mode 100644 index 58c1a02831c..00000000000 --- a/Userland/Libraries/LibCore/SecretString.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2021, Brian Gianforcaro - * Copyright (c) 2021, Mustafa Quraish - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include - -namespace Core { - -ErrorOr SecretString::take_ownership(char*& cstring, size_t length) -{ - auto buffer = TRY(ByteBuffer::copy(cstring, length)); - - secure_zero(cstring, length); - free(cstring); - cstring = nullptr; - - return SecretString(move(buffer)); -} - -SecretString SecretString::take_ownership(ByteBuffer&& buffer) -{ - return SecretString(move(buffer)); -} - -SecretString::SecretString(ByteBuffer&& buffer) - : m_secure_buffer(move(buffer)) -{ - // SecretString is currently only used to provide the character data to invocations to crypt(), - // which requires a NUL-terminated string. To ensure this operation avoids a buffer overrun, - // append a NUL terminator here if there isn't already one. - if (m_secure_buffer.is_empty() || (m_secure_buffer[m_secure_buffer.size() - 1] != 0)) { - u8 nul = '\0'; - m_secure_buffer.append(&nul, 1); - } -} - -SecretString::~SecretString() -{ - // Note: We use secure_zero to avoid the zeroing from being optimized out by the compiler, - // which is possible if memset was to be used here. - if (!m_secure_buffer.is_empty()) { - secure_zero(m_secure_buffer.data(), m_secure_buffer.capacity()); - } -} - -} diff --git a/Userland/Libraries/LibCore/SecretString.h b/Userland/Libraries/LibCore/SecretString.h deleted file mode 100644 index 40378009601..00000000000 --- a/Userland/Libraries/LibCore/SecretString.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2021, Brian Gianforcaro - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Core { - -class SecretString { - AK_MAKE_NONCOPYABLE(SecretString); - AK_MAKE_DEFAULT_MOVABLE(SecretString); - -public: - [[nodiscard]] static ErrorOr take_ownership(char*&, size_t); - [[nodiscard]] static SecretString take_ownership(ByteBuffer&&); - - [[nodiscard]] bool is_empty() const { return m_secure_buffer.is_empty(); } - [[nodiscard]] size_t length() const { return m_secure_buffer.size(); } - [[nodiscard]] char const* characters() const { return reinterpret_cast(m_secure_buffer.data()); } - [[nodiscard]] StringView view() const { return { characters(), length() }; } - - SecretString() = default; - ~SecretString(); - -private: - explicit SecretString(ByteBuffer&&); - - ByteBuffer m_secure_buffer; -}; - -} diff --git a/Userland/Libraries/LibCore/UmaskScope.h b/Userland/Libraries/LibCore/UmaskScope.h deleted file mode 100644 index 45355d08669..00000000000 --- a/Userland/Libraries/LibCore/UmaskScope.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2022, Andreas Kling - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Core { - -class UmaskScope { -public: - explicit UmaskScope(mode_t mask) - { - m_old_mask = umask(mask); - } - - ~UmaskScope() - { - umask(m_old_mask); - } - -private: - mode_t m_old_mask {}; -}; - -}