diff options
author | Drew DeVault <sir@cmpwn.com> | 2016-12-02 17:55:03 -0500 |
---|---|---|
committer | Drew DeVault <sir@cmpwn.com> | 2016-12-02 17:55:03 -0500 |
commit | 62dad7148f7b7b314f0297e191861ae3f03e9e1f (patch) | |
tree | 45bc560d7a197200ff3658cbbb5763e860bf1372 | |
parent | Add IPC security policy command handlers (diff) | |
download | sway-62dad7148f7b7b314f0297e191861ae3f03e9e1f.tar.gz sway-62dad7148f7b7b314f0297e191861ae3f03e9e1f.tar.zst sway-62dad7148f7b7b314f0297e191861ae3f03e9e1f.zip |
Enforce IPC security policy
-rw-r--r-- | include/sway/config.h | 17 | ||||
-rw-r--r-- | sway/commands/ipc.c | 26 | ||||
-rw-r--r-- | sway/ipc-server.c | 35 |
3 files changed, 65 insertions, 13 deletions
diff --git a/include/sway/config.h b/include/sway/config.h index 1154b871..192e697c 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -209,6 +209,23 @@ struct feature_policy { | |||
209 | uint32_t features; | 209 | uint32_t features; |
210 | }; | 210 | }; |
211 | 211 | ||
212 | enum ipc_feature { | ||
213 | IPC_FEATURE_COMMAND = 1, | ||
214 | IPC_FEATURE_GET_WORKSPACES = 2, | ||
215 | IPC_FEATURE_GET_OUTPUTS = 4, | ||
216 | IPC_FEATURE_GET_TREE = 8, | ||
217 | IPC_FEATURE_GET_MARKS = 16, | ||
218 | IPC_FEATURE_GET_BAR_CONFIG = 32, | ||
219 | IPC_FEATURE_GET_VERSION = 64, | ||
220 | IPC_FEATURE_GET_INPUTS = 128, | ||
221 | IPC_FEATURE_EVENT_WORKSPACE = 256, | ||
222 | IPC_FEATURE_EVENT_OUTPUT = 512, | ||
223 | IPC_FEATURE_EVENT_MODE = 1024, | ||
224 | IPC_FEATURE_EVENT_WINDOW = 2048, | ||
225 | IPC_FEATURE_EVENT_BINDING = 4096, | ||
226 | IPC_FEATURE_EVENT_INPUT = 8192 | ||
227 | }; | ||
228 | |||
212 | /** | 229 | /** |
213 | * The configuration struct. The result of loading a config file. | 230 | * The configuration struct. The result of loading a config file. |
214 | */ | 231 | */ |
diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c index e6ae27a4..f96e9980 100644 --- a/sway/commands/ipc.c +++ b/sway/commands/ipc.c | |||
@@ -62,13 +62,13 @@ struct cmd_results *cmd_ipc_cmd(int argc, char **argv) { | |||
62 | char *name; | 62 | char *name; |
63 | enum ipc_command_type type; | 63 | enum ipc_command_type type; |
64 | } types[] = { | 64 | } types[] = { |
65 | { "command", IPC_COMMAND }, | 65 | { "command", IPC_FEATURE_COMMAND }, |
66 | { "workspaces", IPC_GET_WORKSPACES }, | 66 | { "workspaces", IPC_FEATURE_GET_WORKSPACES }, |
67 | { "outputs", IPC_GET_OUTPUTS }, | 67 | { "outputs", IPC_FEATURE_GET_OUTPUTS }, |
68 | { "tree", IPC_GET_TREE }, | 68 | { "tree", IPC_FEATURE_GET_TREE }, |
69 | { "marks", IPC_GET_MARKS }, | 69 | { "marks", IPC_FEATURE_GET_MARKS }, |
70 | { "bar-config", IPC_GET_BAR_CONFIG }, | 70 | { "bar-config", IPC_FEATURE_GET_BAR_CONFIG }, |
71 | { "inputs", IPC_GET_INPUTS }, | 71 | { "inputs", IPC_FEATURE_GET_INPUTS }, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | uint32_t type = 0; | 74 | uint32_t type = 0; |
@@ -111,12 +111,12 @@ struct cmd_results *cmd_ipc_event_cmd(int argc, char **argv) { | |||
111 | char *name; | 111 | char *name; |
112 | enum ipc_command_type type; | 112 | enum ipc_command_type type; |
113 | } types[] = { | 113 | } types[] = { |
114 | { "workspace", event_mask(IPC_EVENT_WORKSPACE) }, | 114 | { "workspace", IPC_FEATURE_EVENT_WORKSPACE }, |
115 | { "output", event_mask(IPC_EVENT_OUTPUT) }, | 115 | { "output", IPC_FEATURE_EVENT_OUTPUT }, |
116 | { "mode", event_mask(IPC_EVENT_MODE) }, | 116 | { "mode", IPC_FEATURE_EVENT_MODE }, |
117 | { "window", event_mask(IPC_EVENT_WINDOW) }, | 117 | { "window", IPC_FEATURE_EVENT_WINDOW }, |
118 | { "binding", event_mask(IPC_EVENT_BINDING) }, | 118 | { "binding", IPC_FEATURE_EVENT_BINDING }, |
119 | { "input", event_mask(IPC_EVENT_INPUT) }, | 119 | { "input", IPC_FEATURE_EVENT_INPUT }, |
120 | }; | 120 | }; |
121 | 121 | ||
122 | uint32_t type = 0; | 122 | uint32_t type = 0; |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index ef741e3b..15791c5e 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -307,9 +307,14 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
307 | } | 307 | } |
308 | buf[client->payload_length] = '\0'; | 308 | buf[client->payload_length] = '\0'; |
309 | 309 | ||
310 | const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }"; | ||
311 | |||
310 | switch (client->current_command) { | 312 | switch (client->current_command) { |
311 | case IPC_COMMAND: | 313 | case IPC_COMMAND: |
312 | { | 314 | { |
315 | if (!(config->ipc_policy & IPC_FEATURE_COMMAND)) { | ||
316 | goto exit_denied; | ||
317 | } | ||
313 | struct cmd_results *results = handle_command(buf, CONTEXT_IPC); | 318 | struct cmd_results *results = handle_command(buf, CONTEXT_IPC); |
314 | const char *json = cmd_results_to_json(results); | 319 | const char *json = cmd_results_to_json(results); |
315 | char reply[256]; | 320 | char reply[256]; |
@@ -359,6 +364,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
359 | 364 | ||
360 | case IPC_GET_WORKSPACES: | 365 | case IPC_GET_WORKSPACES: |
361 | { | 366 | { |
367 | if (!(config->ipc_policy & IPC_FEATURE_GET_WORKSPACES)) { | ||
368 | goto exit_denied; | ||
369 | } | ||
362 | json_object *workspaces = json_object_new_array(); | 370 | json_object *workspaces = json_object_new_array(); |
363 | container_map(&root_container, ipc_get_workspaces_callback, workspaces); | 371 | container_map(&root_container, ipc_get_workspaces_callback, workspaces); |
364 | const char *json_string = json_object_to_json_string(workspaces); | 372 | const char *json_string = json_object_to_json_string(workspaces); |
@@ -369,6 +377,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
369 | 377 | ||
370 | case IPC_GET_INPUTS: | 378 | case IPC_GET_INPUTS: |
371 | { | 379 | { |
380 | if (!(config->ipc_policy & IPC_FEATURE_GET_INPUTS)) { | ||
381 | goto exit_denied; | ||
382 | } | ||
372 | json_object *inputs = json_object_new_array(); | 383 | json_object *inputs = json_object_new_array(); |
373 | if (input_devices) { | 384 | if (input_devices) { |
374 | for(int i=0; i<input_devices->length; i++) { | 385 | for(int i=0; i<input_devices->length; i++) { |
@@ -388,6 +399,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
388 | 399 | ||
389 | case IPC_GET_OUTPUTS: | 400 | case IPC_GET_OUTPUTS: |
390 | { | 401 | { |
402 | if (!(config->ipc_policy & IPC_FEATURE_GET_OUTPUTS)) { | ||
403 | goto exit_denied; | ||
404 | } | ||
391 | json_object *outputs = json_object_new_array(); | 405 | json_object *outputs = json_object_new_array(); |
392 | container_map(&root_container, ipc_get_outputs_callback, outputs); | 406 | container_map(&root_container, ipc_get_outputs_callback, outputs); |
393 | const char *json_string = json_object_to_json_string(outputs); | 407 | const char *json_string = json_object_to_json_string(outputs); |
@@ -398,6 +412,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
398 | 412 | ||
399 | case IPC_GET_TREE: | 413 | case IPC_GET_TREE: |
400 | { | 414 | { |
415 | if (!(config->ipc_policy & IPC_FEATURE_GET_TREE)) { | ||
416 | goto exit_denied; | ||
417 | } | ||
401 | json_object *tree = ipc_json_describe_container_recursive(&root_container); | 418 | json_object *tree = ipc_json_describe_container_recursive(&root_container); |
402 | const char *json_string = json_object_to_json_string(tree); | 419 | const char *json_string = json_object_to_json_string(tree); |
403 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 420 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); |
@@ -458,6 +475,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
458 | 475 | ||
459 | case IPC_GET_BAR_CONFIG: | 476 | case IPC_GET_BAR_CONFIG: |
460 | { | 477 | { |
478 | if (!(config->ipc_policy & IPC_FEATURE_GET_BAR_CONFIG)) { | ||
479 | goto exit_denied; | ||
480 | } | ||
461 | if (!buf[0]) { | 481 | if (!buf[0]) { |
462 | // Send list of configured bar IDs | 482 | // Send list of configured bar IDs |
463 | json_object *bars = json_object_new_array(); | 483 | json_object *bars = json_object_new_array(); |
@@ -498,6 +518,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
498 | goto exit_cleanup; | 518 | goto exit_cleanup; |
499 | } | 519 | } |
500 | 520 | ||
521 | exit_denied: | ||
522 | ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); | ||
523 | |||
501 | exit_cleanup: | 524 | exit_cleanup: |
502 | client->payload_length = 0; | 525 | client->payload_length = 0; |
503 | free(buf); | 526 | free(buf); |
@@ -562,6 +585,9 @@ void ipc_send_event(const char *json_string, enum ipc_command_type event) { | |||
562 | } | 585 | } |
563 | 586 | ||
564 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | 587 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { |
588 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WORKSPACE)) { | ||
589 | return; | ||
590 | } | ||
565 | sway_log(L_DEBUG, "Sending workspace::%s event", change); | 591 | sway_log(L_DEBUG, "Sending workspace::%s event", change); |
566 | json_object *obj = json_object_new_object(); | 592 | json_object *obj = json_object_new_object(); |
567 | json_object_object_add(obj, "change", json_object_new_string(change)); | 593 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -586,6 +612,9 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | |||
586 | } | 612 | } |
587 | 613 | ||
588 | void ipc_event_window(swayc_t *window, const char *change) { | 614 | void ipc_event_window(swayc_t *window, const char *change) { |
615 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WINDOW)) { | ||
616 | return; | ||
617 | } | ||
589 | sway_log(L_DEBUG, "Sending window::%s event", change); | 618 | sway_log(L_DEBUG, "Sending window::%s event", change); |
590 | json_object *obj = json_object_new_object(); | 619 | json_object *obj = json_object_new_object(); |
591 | json_object_object_add(obj, "change", json_object_new_string(change)); | 620 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -611,6 +640,9 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
611 | } | 640 | } |
612 | 641 | ||
613 | void ipc_event_mode(const char *mode) { | 642 | void ipc_event_mode(const char *mode) { |
643 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_MODE)) { | ||
644 | return; | ||
645 | } | ||
614 | sway_log(L_DEBUG, "Sending mode::%s event", mode); | 646 | sway_log(L_DEBUG, "Sending mode::%s event", mode); |
615 | json_object *obj = json_object_new_object(); | 647 | json_object *obj = json_object_new_object(); |
616 | json_object_object_add(obj, "change", json_object_new_string(mode)); | 648 | json_object_object_add(obj, "change", json_object_new_string(mode)); |
@@ -636,6 +668,9 @@ void ipc_event_modifier(uint32_t modifier, const char *state) { | |||
636 | } | 668 | } |
637 | 669 | ||
638 | static void ipc_event_binding(json_object *sb_obj) { | 670 | static void ipc_event_binding(json_object *sb_obj) { |
671 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_BINDING)) { | ||
672 | return; | ||
673 | } | ||
639 | sway_log(L_DEBUG, "Sending binding::run event"); | 674 | sway_log(L_DEBUG, "Sending binding::run event"); |
640 | json_object *obj = json_object_new_object(); | 675 | json_object *obj = json_object_new_object(); |
641 | json_object_object_add(obj, "change", json_object_new_string("run")); | 676 | json_object_object_add(obj, "change", json_object_new_string("run")); |