mirror of
https://github.com/swaywm/sway.git
synced 2026-04-28 06:46:26 -04:00
153 lines
4 KiB
C
153 lines
4 KiB
C
#define _POSIX_C_SOURCE 200809L
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <limits.h>
|
|
#include <unistd.h>
|
|
#include <wlr/util/log.h>
|
|
#include <wayland-server-core.h>
|
|
#include "sway/security.h"
|
|
|
|
struct sway_security_rule {
|
|
char *command;
|
|
char *global;
|
|
struct wl_list link;
|
|
};
|
|
|
|
static struct wl_list rules;
|
|
|
|
static struct sway_security_rule *security_rule_create(const char *cmd,
|
|
const char *global) {
|
|
struct sway_security_rule *rule =
|
|
calloc(1, sizeof(struct sway_security_rule));
|
|
if (rule == NULL) {
|
|
wlr_log(WLR_ERROR, "Allocation failed");
|
|
return NULL;
|
|
}
|
|
if (cmd != NULL) {
|
|
rule->command = strdup(cmd);
|
|
if (rule->command == NULL) {
|
|
goto err;
|
|
}
|
|
}
|
|
if (global != NULL) {
|
|
rule->global = strdup(global);
|
|
if (rule->global == NULL) {
|
|
goto err;
|
|
}
|
|
}
|
|
wl_list_insert(&rules, &rule->link);
|
|
return rule;
|
|
|
|
err:
|
|
wlr_log(WLR_ERROR, "Allocation failed");
|
|
free(rule->global);
|
|
free(rule->command);
|
|
free(rule);
|
|
return NULL;
|
|
}
|
|
|
|
static bool command_from_pid(char cmd[static PATH_MAX + 1], pid_t pid) {
|
|
#ifdef __linux__
|
|
char link_path[PATH_MAX];
|
|
snprintf(link_path, sizeof(link_path), "/proc/%d/exe", pid);
|
|
|
|
ssize_t n = readlink(link_path, cmd, PATH_MAX);
|
|
if (n < 0) {
|
|
wlr_log_errno(WLR_ERROR, "Failed to readlink() %s", link_path);
|
|
return false;
|
|
}
|
|
cmd[n] = '\0';
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
static bool global_filter(const struct wl_client *client,
|
|
const struct wl_global *global, void *data) {
|
|
pid_t pid = 0;
|
|
wl_client_get_credentials((struct wl_client *)client, &pid, NULL, NULL);
|
|
if (pid == 0) {
|
|
wlr_log(WLR_DEBUG, "Host doesn't support Wayland credentials, "
|
|
"cannot enforce security rules");
|
|
return true;
|
|
}
|
|
|
|
char cmd[PATH_MAX + 1];
|
|
if (!command_from_pid(cmd, pid)) {
|
|
wlr_log(WLR_ERROR, "Failed to get command path from PID %d", pid);
|
|
return false;
|
|
}
|
|
|
|
const struct wl_interface *interface = wl_global_get_interface(global);
|
|
bool ok = check_security_rule(cmd, interface->name);
|
|
if (ok) {
|
|
wlr_log(WLR_DEBUG, "Allowing %s to bind to %s", cmd, interface->name);
|
|
} else {
|
|
wlr_log(WLR_DEBUG, "Denying %s from binding to %s", cmd, interface->name);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
bool load_security(struct wl_display *display) {
|
|
wl_list_init(&rules);
|
|
|
|
wl_display_set_global_filter(display, global_filter, NULL);
|
|
|
|
// TODO: move this in a file
|
|
security_rule_create(NULL, "wl_shm");
|
|
security_rule_create(NULL, "wl_drm");
|
|
security_rule_create(NULL, "wl_compositor");
|
|
security_rule_create(NULL, "wl_subcompositor");
|
|
security_rule_create(NULL, "wl_data_device_manager");
|
|
security_rule_create(NULL, "wl_seat");
|
|
security_rule_create(NULL, "wl_output");
|
|
security_rule_create(NULL, "zwp_linux_dmabuf_v1");
|
|
security_rule_create(NULL, "gtk_primary_selection_device_manager");
|
|
security_rule_create(NULL, "zxdg_output_manager_v1");
|
|
security_rule_create(NULL, "org_kde_kwin_idle");
|
|
security_rule_create(NULL, "zwp_idle_inhibit_manager_v1");
|
|
security_rule_create(NULL, "zxdg_shell_v6");
|
|
security_rule_create(NULL, "xdg_wm_base");
|
|
security_rule_create(NULL, "org_kde_kwin_server_decoration_manager");
|
|
security_rule_create(NULL, "zxdg_decoration_manager_v1");
|
|
security_rule_create(NULL, "wp_presentation");
|
|
// gamma_control_manager
|
|
// zwlr_gamma_control_manager_v1
|
|
// zwlr_layer_shell_v1
|
|
// zwlr_export_dmabuf_manager_v1
|
|
// zwlr_screencopy_manager_v1
|
|
// zwp_virtual_keyboard_manager_v1
|
|
// zwlr_input_inhibit_manager_v1
|
|
|
|
return true;
|
|
}
|
|
|
|
bool check_security_rule(const char *cmd, const char *global) {
|
|
struct sway_security_rule *rule;
|
|
wl_list_for_each(rule, &rules, link) {
|
|
if (rule->command != NULL && strcmp(cmd, rule->command) != 0) {
|
|
continue;
|
|
}
|
|
if (rule->global != NULL && strcmp(global, rule->global) != 0) {
|
|
continue;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
struct command_policy *alloc_command_policy(const char *command) {
|
|
struct command_policy *policy = calloc(1, sizeof(struct command_policy));
|
|
if (!policy) {
|
|
return NULL;
|
|
}
|
|
policy->command = strdup(command);
|
|
if (!policy->command) {
|
|
free(policy);
|
|
return NULL;
|
|
}
|
|
policy->context = 0;
|
|
return policy;
|
|
}
|