summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2017-02-20 06:30:25 -0500
committerLibravatar Drew DeVault <sir@cmpwn.com>2017-02-20 06:33:04 -0500
commit1980a0835804b205da1fa00187640ae8a0c4f9be (patch)
tree7d79e173a654443f15bd33c0d7f81f3c1d889af7
parentAdd initial support code for new IPC security (diff)
downloadsway-1980a0835804b205da1fa00187640ae8a0c4f9be.tar.gz
sway-1980a0835804b205da1fa00187640ae8a0c4f9be.tar.zst
sway-1980a0835804b205da1fa00187640ae8a0c4f9be.zip
Enforce new IPC policies
-rw-r--r--sway/commands/ipc.c23
-rw-r--r--sway/ipc-server.c50
2 files changed, 62 insertions, 11 deletions
diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c
index 44d7a010..6b29706e 100644
--- a/sway/commands/ipc.c
+++ b/sway/commands/ipc.c
@@ -1,18 +1,23 @@
1#include <stdio.h> 1#include <stdio.h>
2#include <string.h> 2#include <string.h>
3#include "sway/security.h"
3#include "sway/commands.h" 4#include "sway/commands.h"
4#include "sway/config.h" 5#include "sway/config.h"
5#include "ipc.h" 6#include "ipc.h"
6#include "log.h" 7#include "log.h"
7#include "util.h" 8#include "util.h"
8 9
10static struct ipc_policy *current_policy = NULL;
11
9struct cmd_results *cmd_ipc(int argc, char **argv) { 12struct cmd_results *cmd_ipc(int argc, char **argv) {
10 struct cmd_results *error = NULL; 13 struct cmd_results *error = NULL;
11 if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 1))) { 14 if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 2))) {
12 return error; 15 return error;
13 } 16 }
14 17
15 if (config->reading && strcmp("{", argv[0]) != 0) { 18 const char *program = argv[0];
19
20 if (config->reading && strcmp("{", argv[1]) != 0) {
16 return cmd_results_new(CMD_INVALID, "ipc", 21 return cmd_results_new(CMD_INVALID, "ipc",
17 "Expected '{' at start of IPC config definition."); 22 "Expected '{' at start of IPC config definition.");
18 } 23 }
@@ -26,6 +31,8 @@ struct cmd_results *cmd_ipc(int argc, char **argv) {
26 "This command is only permitted to run from " SYSCONFDIR "/sway/security"); 31 "This command is only permitted to run from " SYSCONFDIR "/sway/security");
27 } 32 }
28 33
34 current_policy = alloc_ipc_policy(program);
35
29 return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL); 36 return cmd_results_new(CMD_BLOCK_IPC, NULL, NULL);
30} 37}
31 38
@@ -86,10 +93,10 @@ struct cmd_results *cmd_ipc_cmd(int argc, char **argv) {
86 } 93 }
87 94
88 if (enabled) { 95 if (enabled) {
89 //config->ipc_policy |= type; 96 current_policy->features |= type;
90 sway_log(L_DEBUG, "Enabled IPC %s feature %d", argv[-1], (int)type); 97 sway_log(L_DEBUG, "Enabled IPC %s feature", argv[-1]);
91 } else { 98 } else {
92 //config->ipc_policy &= ~type; 99 current_policy->features &= ~type;
93 sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]); 100 sway_log(L_DEBUG, "Disabled IPC %s feature", argv[-1]);
94 } 101 }
95 102
@@ -134,10 +141,10 @@ struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) {
134 } 141 }
135 142
136 if (enabled) { 143 if (enabled) {
137 //config->ipc_policy |= type; 144 current_policy->features |= type;
138 sway_log(L_DEBUG, "Enabled IPC %s event %d", argv[-1], (int)type); 145 sway_log(L_DEBUG, "Enabled IPC %s event", argv[-1]);
139 } else { 146 } else {
140 //config->ipc_policy &= ~type; 147 current_policy->features &= ~type;
141 sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]); 148 sway_log(L_DEBUG, "Disabled IPC %s event", argv[-1]);
142 } 149 }
143 150
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index dfe88ed6..20a19b44 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -35,6 +35,7 @@ struct ipc_client {
35 struct wlc_event_source *event_source; 35 struct wlc_event_source *event_source;
36 int fd; 36 int fd;
37 uint32_t payload_length; 37 uint32_t payload_length;
38 uint32_t security_policy;
38 enum ipc_command_type current_command; 39 enum ipc_command_type current_command;
39 enum ipc_command_type subscribed_events; 40 enum ipc_command_type subscribed_events;
40}; 41};
@@ -125,7 +126,6 @@ struct sockaddr_un *ipc_user_sockaddr(void) {
125 return ipc_sockaddr; 126 return ipc_sockaddr;
126} 127}
127 128
128/*
129static pid_t get_client_pid(int client_fd) { 129static pid_t get_client_pid(int client_fd) {
130// FreeBSD supports getting uid/gid, but not pid 130// FreeBSD supports getting uid/gid, but not pid
131#ifdef __linux__ 131#ifdef __linux__
@@ -141,7 +141,6 @@ static pid_t get_client_pid(int client_fd) {
141 return -1; 141 return -1;
142#endif 142#endif
143} 143}
144*/
145 144
146int ipc_handle_connection(int fd, uint32_t mask, void *data) { 145int ipc_handle_connection(int fd, uint32_t mask, void *data) {
147 (void) fd; (void) data; 146 (void) fd; (void) data;
@@ -172,6 +171,9 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) {
172 client->subscribed_events = 0; 171 client->subscribed_events = 0;
173 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client); 172 client->event_source = wlc_event_loop_add_fd(client_fd, WLC_EVENT_READABLE, ipc_client_handle_readable, client);
174 173
174 pid_t pid = get_client_pid(client->fd);
175 client->security_policy = get_ipc_policy(pid);
176
175 list_add(ipc_client_list, client); 177 list_add(ipc_client_list, client);
176 178
177 return 0; 179 return 0;
@@ -342,6 +344,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
342 switch (client->current_command) { 344 switch (client->current_command) {
343 case IPC_COMMAND: 345 case IPC_COMMAND:
344 { 346 {
347 if (!(client->security_policy & IPC_FEATURE_COMMAND)) {
348 goto exit_denied;
349 }
345 struct cmd_results *results = handle_command(buf, CONTEXT_IPC); 350 struct cmd_results *results = handle_command(buf, CONTEXT_IPC);
346 const char *json = cmd_results_to_json(results); 351 const char *json = cmd_results_to_json(results);
347 char reply[256]; 352 char reply[256];
@@ -353,6 +358,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
353 358
354 case IPC_SUBSCRIBE: 359 case IPC_SUBSCRIBE:
355 { 360 {
361 // TODO: Check if they're permitted to use these events
356 struct json_object *request = json_tokener_parse(buf); 362 struct json_object *request = json_tokener_parse(buf);
357 if (request == NULL) { 363 if (request == NULL) {
358 ipc_send_reply(client, "{\"success\": false}", 18); 364 ipc_send_reply(client, "{\"success\": false}", 18);
@@ -391,6 +397,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
391 397
392 case IPC_GET_WORKSPACES: 398 case IPC_GET_WORKSPACES:
393 { 399 {
400 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) {
401 goto exit_denied;
402 }
394 json_object *workspaces = json_object_new_array(); 403 json_object *workspaces = json_object_new_array();
395 container_map(&root_container, ipc_get_workspaces_callback, workspaces); 404 container_map(&root_container, ipc_get_workspaces_callback, workspaces);
396 const char *json_string = json_object_to_json_string(workspaces); 405 const char *json_string = json_object_to_json_string(workspaces);
@@ -401,6 +410,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
401 410
402 case IPC_GET_INPUTS: 411 case IPC_GET_INPUTS:
403 { 412 {
413 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) {
414 goto exit_denied;
415 }
404 json_object *inputs = json_object_new_array(); 416 json_object *inputs = json_object_new_array();
405 if (input_devices) { 417 if (input_devices) {
406 for(int i=0; i<input_devices->length; i++) { 418 for(int i=0; i<input_devices->length; i++) {
@@ -424,6 +436,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
424 436
425 case IPC_GET_OUTPUTS: 437 case IPC_GET_OUTPUTS:
426 { 438 {
439 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) {
440 goto exit_denied;
441 }
427 json_object *outputs = json_object_new_array(); 442 json_object *outputs = json_object_new_array();
428 container_map(&root_container, ipc_get_outputs_callback, outputs); 443 container_map(&root_container, ipc_get_outputs_callback, outputs);
429 const char *json_string = json_object_to_json_string(outputs); 444 const char *json_string = json_object_to_json_string(outputs);
@@ -434,6 +449,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
434 449
435 case IPC_GET_TREE: 450 case IPC_GET_TREE:
436 { 451 {
452 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) {
453 goto exit_denied;
454 }
437 json_object *tree = ipc_json_describe_container_recursive(&root_container); 455 json_object *tree = ipc_json_describe_container_recursive(&root_container);
438 const char *json_string = json_object_to_json_string(tree); 456 const char *json_string = json_object_to_json_string(tree);
439 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); 457 ipc_send_reply(client, json_string, (uint32_t) strlen(json_string));
@@ -498,6 +516,9 @@ void ipc_client_handle_command(struct ipc_client *client) {
498 516
499 case IPC_GET_BAR_CONFIG: 517 case IPC_GET_BAR_CONFIG:
500 { 518 {
519 if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) {
520 goto exit_denied;
521 }
501 if (!buf[0]) { 522 if (!buf[0]) {
502 // Send list of configured bar IDs 523 // Send list of configured bar IDs
503 json_object *bars = json_object_new_array(); 524 json_object *bars = json_object_new_array();
@@ -538,7 +559,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
538 goto exit_cleanup; 559 goto exit_cleanup;
539 } 560 }
540 561
541//exit_denied: 562exit_denied:
542 ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); 563 ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied));
543 564
544exit_cleanup: 565exit_cleanup:
@@ -589,10 +610,33 @@ void ipc_get_outputs_callback(swayc_t *container, void *data) {
589} 610}
590 611
591void ipc_send_event(const char *json_string, enum ipc_command_type event) { 612void ipc_send_event(const char *json_string, enum ipc_command_type event) {
613 static struct {
614 enum ipc_command_type event;
615 enum ipc_feature feature;
616 } security_mappings[] = {
617 { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE },
618 { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT },
619 { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE },
620 { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW },
621 { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING },
622 { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT }
623 };
624
625 uint32_t security_mask = 0;
626 for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) {
627 if (security_mappings[i].event == event) {
628 security_mask = security_mappings[i].feature;
629 break;
630 }
631 }
632
592 int i; 633 int i;
593 struct ipc_client *client; 634 struct ipc_client *client;
594 for (i = 0; i < ipc_client_list->length; i++) { 635 for (i = 0; i < ipc_client_list->length; i++) {
595 client = ipc_client_list->items[i]; 636 client = ipc_client_list->items[i];
637 if (!(client->security_policy & security_mask)) {
638 continue;
639 }
596 if ((client->subscribed_events & event_mask(event)) == 0) { 640 if ((client->subscribed_events & event_mask(event)) == 0) {
597 continue; 641 continue;
598 } 642 }