summaryrefslogtreecommitdiff
path: root/src/managers/permissions/DynamicPermissionManager.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2025-04-29 18:59:43 +0200
committerGitHub <noreply@github.com>2025-04-29 18:59:43 +0200
commit5bd7ff884dc613ad22ecd227d41ce6ad7ee336df (patch)
tree63696482d6ca82db0f123ed53ce798ba500b7c44 /src/managers/permissions/DynamicPermissionManager.cpp
parent21184404885cf61f7c10d2eb749478ef6b035dd2 (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.cpp132
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;