mirror of
https://github.com/swaywm/sway.git
synced 2026-04-26 06:46:26 -04:00
Security v2
This commit is contained in:
parent
7ca9ef12f8
commit
4f4b335737
8 changed files with 315 additions and 4 deletions
|
|
@ -302,4 +302,6 @@ sway_cmd cmd_ipc_cmd;
|
|||
sway_cmd cmd_ipc_events;
|
||||
sway_cmd cmd_ipc_event_cmd;
|
||||
|
||||
sway_cmd cmd_security;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
24
include/sway/security.h
Normal file
24
include/sway/security.h
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
enum security_perm {
|
||||
PRIV_LAYER_SHELL,
|
||||
PRIV_OUTPUT_MANAGER,
|
||||
PRIV_INPUT_METHOD,
|
||||
PRIV_TEXT_INPUT,
|
||||
PRIV_FOREIGN_TOPLEVEL_MANAGER,
|
||||
PRIV_DMABUF_MANAGER,
|
||||
PRIV_SCREENCOPY_MANAGER,
|
||||
PRIV_DATA_CONTROL_MANAGER,
|
||||
PRIV_GAMMA_CONTROL_MANAGER,
|
||||
PRIV_INPUT_INHIBIT,
|
||||
PRIV_INPUT_KEYBOARD_SHORTCUTS_INHIBIT,
|
||||
PRIV_INPUT_VIRTUAL_KEYBOARD,
|
||||
PRIV_INPUT_VIRTUAL_POINTER,
|
||||
PRIV_OUTPUT_POWER_MANAGER,
|
||||
PRIV_LAST, /* not an actual permission */
|
||||
};
|
||||
|
||||
bool security_global_filter(const struct wl_client *client, const struct wl_global *global, void *data);
|
||||
|
||||
void security_set_permit(struct wl_client *client, uint32_t allowed);
|
||||
uint32_t security_get_permit(const struct wl_client *client);
|
||||
|
|
@ -37,6 +37,7 @@ struct sway_server {
|
|||
struct wl_listener compositor_new_surface;
|
||||
|
||||
struct wlr_data_device_manager *data_device_manager;
|
||||
struct wlr_gamma_control_manager_v1 *gamma_control_manager;
|
||||
|
||||
struct sway_input_manager *input;
|
||||
|
||||
|
|
@ -85,6 +86,10 @@ struct sway_server {
|
|||
struct wlr_text_input_manager_v3 *text_input;
|
||||
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
|
||||
|
||||
struct wlr_export_dmabuf_manager_v1 *dmabuf_manager;
|
||||
struct wlr_screencopy_manager_v1 *screencopy_manager;
|
||||
struct wlr_data_control_manager_v1 *data_control_manager;
|
||||
|
||||
size_t txn_timeout_ms;
|
||||
list_t *transactions;
|
||||
list_t *dirty_nodes;
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static struct cmd_handler handlers[] = {
|
|||
{ "output", cmd_output },
|
||||
{ "popup_during_fullscreen", cmd_popup_during_fullscreen },
|
||||
{ "seat", cmd_seat },
|
||||
{ "security", cmd_security },
|
||||
{ "set", cmd_set },
|
||||
{ "show_marks", cmd_show_marks },
|
||||
{ "smart_borders", cmd_smart_borders },
|
||||
|
|
|
|||
129
sway/commands/security.c
Normal file
129
sway/commands/security.c
Normal file
|
|
@ -0,0 +1,129 @@
|
|||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include "sway/commands.h"
|
||||
#include "sway/security.h"
|
||||
#include "sway/tree/container.h"
|
||||
#include "sway/tree/view.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
|
||||
struct find_by_cid_data {
|
||||
uint32_t cid;
|
||||
struct wl_client *target;
|
||||
};
|
||||
|
||||
static void find_by_cid_iter(struct sway_container *container, void* data) {
|
||||
struct find_by_cid_data *ctx = data;
|
||||
if (!container->view)
|
||||
return;
|
||||
if (ctx->cid != container->node.id)
|
||||
return;
|
||||
if (!container->view->surface)
|
||||
return;
|
||||
ctx->target = wl_resource_get_client(container->view->surface->resource);
|
||||
}
|
||||
|
||||
static void do_cmd(struct wl_client *target, int mode, uint32_t privs) {
|
||||
uint32_t allow;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
security_set_permit(target, privs);
|
||||
break;
|
||||
case 1:
|
||||
allow = security_get_permit(target);
|
||||
allow |= privs;
|
||||
security_set_permit(target, allow);
|
||||
break;
|
||||
case 2:
|
||||
allow = security_get_permit(target);
|
||||
allow &= ~privs;
|
||||
security_set_permit(target, allow);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct cmd_results *cmd_security(int argc, char **argv) {
|
||||
struct cmd_results *error = NULL;
|
||||
if ((error = checkarg(argc, "security", EXPECTED_AT_LEAST, 3))) {
|
||||
return error;
|
||||
}
|
||||
|
||||
char* op = argv[0];
|
||||
char* who = argv[1];
|
||||
uint32_t privs = 0;
|
||||
int mode;
|
||||
if (strcmp(op, "set") == 0) {
|
||||
mode = 0;
|
||||
} else if (strcmp(op, "permit") == 0) {
|
||||
mode = 1;
|
||||
} else if (strcmp(op, "deny") == 0) {
|
||||
mode = 2;
|
||||
} else {
|
||||
return cmd_results_new(CMD_INVALID, "Invalid operation", op);
|
||||
}
|
||||
|
||||
for(int i = 2; i < argc; i++) {
|
||||
char* arg = argv[i];
|
||||
if (strcmp(arg, "*") == 0)
|
||||
privs |= ~0;
|
||||
else if (strcmp(arg, "layer_shell") == 0)
|
||||
privs |= 1 << PRIV_LAYER_SHELL;
|
||||
else if (strcmp(arg, "output_manager") == 0)
|
||||
privs |= 1 << PRIV_OUTPUT_MANAGER;
|
||||
else if (strcmp(arg, "input_method") == 0)
|
||||
privs |= 1 << PRIV_INPUT_METHOD;
|
||||
else if (strcmp(arg, "text_input") == 0)
|
||||
privs |= 1 << PRIV_TEXT_INPUT;
|
||||
else if (strcmp(arg, "foreign_toplevel_manager") == 0)
|
||||
privs |= 1 << PRIV_FOREIGN_TOPLEVEL_MANAGER;
|
||||
else if (strcmp(arg, "dmabuf_manager") == 0)
|
||||
privs |= 1 << PRIV_DMABUF_MANAGER;
|
||||
else if (strcmp(arg, "screencopy_manager") == 0)
|
||||
privs |= 1 << PRIV_SCREENCOPY_MANAGER;
|
||||
else if (strcmp(arg, "data_control_manager") == 0)
|
||||
privs |= 1 << PRIV_DATA_CONTROL_MANAGER;
|
||||
else if (strcmp(arg, "gamma_control_manager") == 0)
|
||||
privs |= 1 << PRIV_GAMMA_CONTROL_MANAGER;
|
||||
else if (strcmp(arg, "input_inhibit") == 0)
|
||||
privs |= 1 << PRIV_INPUT_INHIBIT;
|
||||
else if (strcmp(arg, "input_keyboard_shortcuts_inhibit") == 0)
|
||||
privs |= 1 << PRIV_INPUT_KEYBOARD_SHORTCUTS_INHIBIT;
|
||||
else if (strcmp(arg, "input_virtual_keyboard") == 0)
|
||||
privs |= 1 << PRIV_INPUT_VIRTUAL_KEYBOARD;
|
||||
else if (strcmp(arg, "input_virtual_pointer") == 0)
|
||||
privs |= 1 << PRIV_INPUT_VIRTUAL_POINTER;
|
||||
else if (strcmp(arg, "output_power_manager") == 0)
|
||||
privs |= 1 << PRIV_OUTPUT_POWER_MANAGER;
|
||||
else
|
||||
return cmd_results_new(CMD_INVALID, "Unknown permission", arg);
|
||||
}
|
||||
|
||||
if (strcmp(who, "*") == 0) {
|
||||
do_cmd(NULL, mode, privs);
|
||||
} else if (strncmp(who, "cid=", 4) == 0) {
|
||||
struct find_by_cid_data data = {
|
||||
.cid = strtoul(who + 4, NULL, 0),
|
||||
};
|
||||
root_for_each_container(find_by_cid_iter, &data);
|
||||
if (!data.target)
|
||||
return cmd_results_new(CMD_INVALID, "Client not found", who);
|
||||
do_cmd(data.target, mode, privs);
|
||||
} else if (strncmp(who, "pid=", 4) == 0) {
|
||||
pid_t target_pid = strtoul(who + 4, NULL, 0);
|
||||
struct wl_client* client;
|
||||
struct wl_list *clients = wl_display_get_client_list(server.wl_display);
|
||||
wl_client_for_each(client, clients) {
|
||||
pid_t pid;
|
||||
wl_client_get_credentials(client, &pid, NULL, NULL);
|
||||
if (pid == target_pid)
|
||||
do_cmd(client, mode, privs);
|
||||
}
|
||||
} else {
|
||||
// TODO support other criteria? Only secure things like pid
|
||||
return cmd_results_new(CMD_INVALID, "Invalid target exmpression", who);
|
||||
}
|
||||
|
||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ sway_sources = files(
|
|||
'ipc-json.c',
|
||||
'ipc-server.c',
|
||||
'main.c',
|
||||
'security.c',
|
||||
'server.c',
|
||||
'swaynag.c',
|
||||
'xdg_decoration.c',
|
||||
|
|
@ -96,6 +97,7 @@ sway_sources = files(
|
|||
'commands/seat/pointer_constraint.c',
|
||||
'commands/seat/shortcuts_inhibitor.c',
|
||||
'commands/seat/xcursor_theme.c',
|
||||
'commands/security.c',
|
||||
'commands/set.c',
|
||||
'commands/show_marks.c',
|
||||
'commands/shortcuts_inhibitor.c',
|
||||
|
|
|
|||
145
sway/security.c
Normal file
145
sway/security.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/multi.h>
|
||||
#include <wlr/backend/noop.h>
|
||||
#include <wlr/backend/session.h>
|
||||
#include <wlr/render/wlr_renderer.h>
|
||||
#include <wlr/types/wlr_compositor.h>
|
||||
#include <wlr/types/wlr_data_control_v1.h>
|
||||
#include <wlr/types/wlr_export_dmabuf_v1.h>
|
||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||
#include <wlr/types/wlr_gtk_primary_selection.h>
|
||||
#include <wlr/types/wlr_idle.h>
|
||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||
#include <wlr/types/wlr_screencopy_v1.h>
|
||||
#include <wlr/types/wlr_server_decoration.h>
|
||||
#include <wlr/types/wlr_tablet_v2.h>
|
||||
#include <wlr/types/wlr_viewporter.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||
#include <wlr/types/wlr_xdg_output_v1.h>
|
||||
#include "config.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "sway/config.h"
|
||||
#include "sway/desktop/idle_inhibit_v1.h"
|
||||
#include "sway/input/input-manager.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/security.h"
|
||||
#include "sway/tree/root.h"
|
||||
|
||||
struct security_permit {
|
||||
uint32_t allowed;
|
||||
const struct wl_client *client;
|
||||
struct wl_listener on_destroy;
|
||||
};
|
||||
|
||||
static uint32_t security_allow_default = ~0;
|
||||
static list_t *security_permit_list;
|
||||
|
||||
bool security_global_filter(const struct wl_client *client, const struct wl_global *global, void *data)
|
||||
{
|
||||
struct sway_server *server = data;
|
||||
enum security_perm perm;
|
||||
|
||||
if (global == server->layer_shell->global)
|
||||
perm = PRIV_LAYER_SHELL;
|
||||
else if (global == server->output_manager_v1->global)
|
||||
perm = PRIV_OUTPUT_MANAGER;
|
||||
else if (global == server->input_method->global)
|
||||
perm = PRIV_INPUT_METHOD;
|
||||
else if (global == server->text_input->global)
|
||||
perm = PRIV_TEXT_INPUT;
|
||||
else if (global == server->foreign_toplevel_manager->global)
|
||||
perm = PRIV_FOREIGN_TOPLEVEL_MANAGER;
|
||||
else if (global == server->dmabuf_manager->global)
|
||||
perm = PRIV_DMABUF_MANAGER;
|
||||
else if (global == server->screencopy_manager->global )
|
||||
perm = PRIV_SCREENCOPY_MANAGER;
|
||||
else if (global == server->data_control_manager->global)
|
||||
perm = PRIV_DATA_CONTROL_MANAGER;
|
||||
else if (global == server->gamma_control_manager->global)
|
||||
perm = PRIV_GAMMA_CONTROL_MANAGER;
|
||||
else if (global == server->input->inhibit->global)
|
||||
perm = PRIV_INPUT_INHIBIT;
|
||||
else if (global == server->input->keyboard_shortcuts_inhibit->global)
|
||||
perm = PRIV_INPUT_KEYBOARD_SHORTCUTS_INHIBIT;
|
||||
else if (global == server->input->virtual_keyboard->global)
|
||||
perm = PRIV_INPUT_VIRTUAL_KEYBOARD;
|
||||
else if (global == server->input->virtual_pointer->global)
|
||||
perm = PRIV_INPUT_VIRTUAL_POINTER;
|
||||
else if (global == server->output_power_manager_v1->global)
|
||||
perm = PRIV_OUTPUT_POWER_MANAGER;
|
||||
else
|
||||
return true;
|
||||
|
||||
uint32_t priv_bit = 1 << perm;
|
||||
uint32_t allowed = security_get_permit(client);
|
||||
if (allowed & priv_bit)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void security_client_destroy(struct wl_listener *listener, void *client_v)
|
||||
{
|
||||
const struct wl_client *client = client_v;
|
||||
if (!security_permit_list)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < security_permit_list->length; ++i) {
|
||||
struct security_permit *item = security_permit_list->items[i];
|
||||
if (client != item->client)
|
||||
continue;
|
||||
list_del(security_permit_list, i);
|
||||
free(item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t security_get_permit(const struct wl_client *client)
|
||||
{
|
||||
if (client && security_permit_list) {
|
||||
for (int i = 0; i < security_permit_list->length; ++i) {
|
||||
struct security_permit *item = security_permit_list->items[i];
|
||||
if (client == item->client)
|
||||
return item->allowed;
|
||||
}
|
||||
}
|
||||
return security_allow_default;
|
||||
}
|
||||
|
||||
void security_set_permit(struct wl_client *client, uint32_t allowed) {
|
||||
struct security_permit *found = NULL;
|
||||
if (client == NULL) {
|
||||
security_allow_default = allowed;
|
||||
return;
|
||||
}
|
||||
if (!security_permit_list)
|
||||
security_permit_list = create_list();
|
||||
for (int i = 0; i < security_permit_list->length; ++i) {
|
||||
struct security_permit *item = security_permit_list->items[i];
|
||||
if (client == item->client) {
|
||||
found = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
found = malloc(sizeof(*found));
|
||||
found->client = client;
|
||||
found->on_destroy.notify = security_client_destroy;
|
||||
list_add(security_permit_list, found);
|
||||
wl_client_add_destroy_listener(client, &found->on_destroy);
|
||||
}
|
||||
found->allowed = allowed;
|
||||
}
|
||||
|
|
@ -34,6 +34,7 @@
|
|||
#include "sway/input/input-manager.h"
|
||||
#include "sway/output.h"
|
||||
#include "sway/server.h"
|
||||
#include "sway/security.h"
|
||||
#include "sway/tree/root.h"
|
||||
#if HAVE_XWAYLAND
|
||||
#include "sway/xwayland.h"
|
||||
|
|
@ -68,7 +69,7 @@ bool server_init(struct sway_server *server) {
|
|||
server->data_device_manager =
|
||||
wlr_data_device_manager_create(server->wl_display);
|
||||
|
||||
wlr_gamma_control_manager_v1_create(server->wl_display);
|
||||
server->gamma_control_manager = wlr_gamma_control_manager_v1_create(server->wl_display);
|
||||
wlr_gtk_primary_selection_device_manager_create(server->wl_display);
|
||||
|
||||
server->new_output.notify = handle_new_output;
|
||||
|
|
@ -145,12 +146,14 @@ bool server_init(struct sway_server *server) {
|
|||
server->foreign_toplevel_manager =
|
||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||
|
||||
wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
wlr_data_control_manager_v1_create(server->wl_display);
|
||||
server->dmabuf_manager = wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||
server->screencopy_manager = wlr_screencopy_manager_v1_create(server->wl_display);
|
||||
server->data_control_manager = wlr_data_control_manager_v1_create(server->wl_display);
|
||||
wlr_primary_selection_v1_device_manager_create(server->wl_display);
|
||||
wlr_viewporter_create(server->wl_display);
|
||||
|
||||
wl_display_set_global_filter(server->wl_display, security_global_filter, server);
|
||||
|
||||
server->socket = wl_display_add_socket_auto(server->wl_display);
|
||||
if (!server->socket) {
|
||||
sway_log(SWAY_ERROR, "Unable to open wayland socket");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue