diff options
| author | Vaxry <43317083+vaxerski@users.noreply.github.com> | 2025-04-29 18:59:43 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-04-29 18:59:43 +0200 |
| commit | 5bd7ff884dc613ad22ecd227d41ce6ad7ee336df (patch) | |
| tree | 63696482d6ca82db0f123ed53ce798ba500b7c44 /src/managers/permissions/DynamicPermissionManager.cpp | |
| parent | 21184404885cf61f7c10d2eb749478ef6b035dd2 (diff) | |
permissions: add perms for plugin loading (#10184)
Adds permission management for loading plugins
---------
Co-authored-by: Jan Beich <jbeich@FreeBSD.org>
Diffstat (limited to 'src/managers/permissions/DynamicPermissionManager.cpp')
| -rw-r--r-- | src/managers/permissions/DynamicPermissionManager.cpp | 132 |
1 files changed, 122 insertions, 10 deletions
diff --git a/src/managers/permissions/DynamicPermissionManager.cpp b/src/managers/permissions/DynamicPermissionManager.cpp index c23f1fdb..e111343e 100644 --- a/src/managers/permissions/DynamicPermissionManager.cpp +++ b/src/managers/permissions/DynamicPermissionManager.cpp @@ -7,6 +7,9 @@ #include "../../Compositor.hpp" #include "../../config/ConfigValue.hpp" +#include <hyprutils/string/String.hpp> +using namespace Hyprutils::String; + #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) #include <sys/sysctl.h> #endif @@ -64,10 +67,7 @@ static const char* permissionToHumanString(eDynamicPermissionType type) { return "error"; } -static std::expected<std::string, std::string> binaryNameForWlClient(wl_client* client) { - pid_t pid = 0; - wl_client_get_credentials(client, &pid, nullptr, nullptr); - +static std::expected<std::string, std::string> binaryNameForPid(pid_t pid) { if (pid <= 0) return std::unexpected("No pid for client"); @@ -102,6 +102,13 @@ static std::expected<std::string, std::string> binaryNameForWlClient(wl_client* return fullPath; } +static std::expected<std::string, std::string> binaryNameForWlClient(wl_client* client) { + pid_t pid = 0; + wl_client_get_credentials(client, &pid, nullptr, nullptr); + + return binaryNameForPid(pid); +} + void CDynamicPermissionManager::clearConfigPermissions() { std::erase_if(m_rules, [](const auto& e) { return e->m_source == PERMISSION_RULE_SOURCE_CONFIG; }); } @@ -183,22 +190,99 @@ eDynamicPermissionAllowMode CDynamicPermissionManager::clientPermissionMode(wl_c return PERMISSION_RULE_ALLOW_MODE_PENDING; } -void CDynamicPermissionManager::askForPermission(wl_client* client, const std::string& binaryPath, eDynamicPermissionType type) { - auto rule = m_rules.emplace_back(SP<CDynamicPermissionRule>(new CDynamicPermissionRule(client, type, PERMISSION_RULE_ALLOW_MODE_PENDING))); +eDynamicPermissionAllowMode CDynamicPermissionManager::clientPermissionModeWithString(pid_t pid, const std::string& str, eDynamicPermissionType permission) { + static auto PPERM = CConfigValue<Hyprlang::INT>("ecosystem:enforce_permissions"); + + if (*PPERM == 0) + return PERMISSION_RULE_ALLOW_MODE_ALLOW; + + const auto LOOKUP = binaryNameForPid(pid); + + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: checking permission {} for key {} (binary {})", permissionToString(permission), str, + LOOKUP.has_value() ? LOOKUP.value() : "lookup failed: " + LOOKUP.error()); + + // first, check if we have the client + perm combo in our cache. + auto it = std::ranges::find_if(m_rules, [str, permission, pid](const auto& e) { return e->m_keyString == str && pid && pid == e->m_pid && e->m_type == permission; }); + if (it == m_rules.end()) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission not cached, checking key"); + + it = std::ranges::find_if(m_rules, [key = str, permission, &LOOKUP](const auto& e) { + if (e->m_type != permission) + return false; // wrong perm + + if (!e->m_binaryRegex) + return false; // no regex + + // regex match + if (RE2::FullMatch(key, *e->m_binaryRegex) || (LOOKUP.has_value() && RE2::FullMatch(LOOKUP.value(), *e->m_binaryRegex))) + return true; + + return false; + }); + + if (it == m_rules.end()) + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: no rule for key"); + else { + if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_ALLOW) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission allowed by config rule"); + return PERMISSION_RULE_ALLOW_MODE_ALLOW; + } else if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_DENY) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission denied by config rule"); + return PERMISSION_RULE_ALLOW_MODE_DENY; + } else if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_PENDING) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission pending by config rule"); + return PERMISSION_RULE_ALLOW_MODE_PENDING; + } else + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission ask by config rule"); + } + + } else if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_ALLOW) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission allowed before by user"); + return PERMISSION_RULE_ALLOW_MODE_ALLOW; + } else if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_DENY) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission denied before by user"); + return PERMISSION_RULE_ALLOW_MODE_DENY; + } else if ((*it)->m_allowMode == PERMISSION_RULE_ALLOW_MODE_PENDING) { + Debug::log(TRACE, "CDynamicPermissionManager::clientHasPermission: permission pending before by user"); + return PERMISSION_RULE_ALLOW_MODE_PENDING; + } + + // if we are here, we need to ask. + askForPermission(nullptr, str, permission, pid); + + return PERMISSION_RULE_ALLOW_MODE_PENDING; +} + +void CDynamicPermissionManager::askForPermission(wl_client* client, const std::string& binaryPath, eDynamicPermissionType type, pid_t pid) { + auto rule = m_rules.emplace_back(SP<CDynamicPermissionRule>(new CDynamicPermissionRule(client, type, PERMISSION_RULE_ALLOW_MODE_PENDING))); + + if (!client) + rule->m_keyString = binaryPath; + + rule->m_pid = pid; std::string description = ""; if (binaryPath.empty()) description = std::format("An unknown application (wayland client ID 0x{:x}) is {}.", (uintptr_t)client, permissionToHumanString(type)); - else { + else if (client) { std::string binaryName = binaryPath.contains("/") ? binaryPath.substr(binaryPath.find_last_of('/') + 1) : binaryPath; description = std::format("An application <b>{}</b> ({}) is {}.", binaryName, binaryPath, permissionToHumanString(type)); - } + } else if (pid >= 0) { + if (type == PERMISSION_TYPE_PLUGIN) { + const auto LOOKUP = binaryNameForPid(pid); + description = std::format("An application <b>{}</b> is {}:<br/><b>{}</b>", LOOKUP.value_or("Unknown"), permissionToHumanString(type), binaryPath); + } else { + const auto LOOKUP = binaryNameForPid(pid); + description = std::format("An application <b>{}</b> ({}) is {}.", LOOKUP.value_or("Unknown"), binaryPath, permissionToHumanString(type)); + } + } else + description = std::format("An application is {}:<br/><b>{}</b>", permissionToHumanString(type), binaryPath); description += "<br/><br/>Do you want to allow this?"; std::vector<std::string> options; - if (!binaryPath.empty()) { + if (!binaryPath.empty() && client) { description += "<br/><br/><i>Hint: you can set persistent rules for these in the Hyprland config file.</i>"; options = {"Deny", "Allow and remember app", "Allow once"}; } else @@ -250,7 +334,35 @@ void CDynamicPermissionManager::askForPermission(wl_client* client, const std::s } SP<CPromise<eDynamicPermissionAllowMode>> CDynamicPermissionManager::promiseFor(wl_client* client, eDynamicPermissionType permission) { - auto rule = std::ranges::find_if(m_rules, [client, permission](const auto& e) { return e->m_client == client && e->m_type == permission; }); + auto rule = std::ranges::find_if(m_rules, [&client, &permission](const auto& e) { return e->m_client == client && e->m_type == permission; }); + if (rule == m_rules.end()) + return nullptr; + + if (!(*rule)->m_promise) + return nullptr; + + if ((*rule)->m_promiseResolverForExternal) + return nullptr; + + return CPromise<eDynamicPermissionAllowMode>::make([rule](SP<CPromiseResolver<eDynamicPermissionAllowMode>> r) { (*rule)->m_promiseResolverForExternal = r; }); +} + +SP<CPromise<eDynamicPermissionAllowMode>> CDynamicPermissionManager::promiseFor(const std::string& key, eDynamicPermissionType permission) { + auto rule = std::ranges::find_if(m_rules, [&key, &permission](const auto& e) { return e->m_keyString == key && e->m_type == permission; }); + if (rule == m_rules.end()) + return nullptr; + + if (!(*rule)->m_promise) + return nullptr; + + if ((*rule)->m_promiseResolverForExternal) + return nullptr; + + return CPromise<eDynamicPermissionAllowMode>::make([rule](SP<CPromiseResolver<eDynamicPermissionAllowMode>> r) { (*rule)->m_promiseResolverForExternal = r; }); +} + +SP<CPromise<eDynamicPermissionAllowMode>> CDynamicPermissionManager::promiseFor(pid_t pid, const std::string& key, eDynamicPermissionType permission) { + auto rule = std::ranges::find_if(m_rules, [&pid, &permission, &key](const auto& e) { return e->m_pid == pid && e->m_keyString == key && e->m_type == permission; }); if (rule == m_rules.end()) return nullptr; |
