diff options
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r-- | sway/ipc-server.c | 72 |
1 files changed, 39 insertions, 33 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index be6e411a..eddae461 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 | }; |
@@ -159,17 +160,6 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
159 | return 0; | 160 | return 0; |
160 | } | 161 | } |
161 | 162 | ||
162 | pid_t pid = get_client_pid(client_fd); | ||
163 | if (!(get_feature_policy(pid) & FEATURE_IPC)) { | ||
164 | sway_log(L_INFO, "Permission to connect to IPC socket denied to %d", pid); | ||
165 | const char *error = "{\"success\": false, \"message\": \"Permission denied\"}"; | ||
166 | if (write(client_fd, &error, sizeof(error)) < (int)sizeof(error)) { | ||
167 | sway_log(L_DEBUG, "Failed to write entire error"); | ||
168 | } | ||
169 | close(client_fd); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); | 163 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); |
174 | if (!client) { | 164 | if (!client) { |
175 | sway_log(L_ERROR, "Unable to allocate ipc client"); | 165 | sway_log(L_ERROR, "Unable to allocate ipc client"); |
@@ -181,6 +171,9 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
181 | client->subscribed_events = 0; | 171 | client->subscribed_events = 0; |
182 | 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); |
183 | 173 | ||
174 | pid_t pid = get_client_pid(client->fd); | ||
175 | client->security_policy = get_ipc_policy(pid); | ||
176 | |||
184 | list_add(ipc_client_list, client); | 177 | list_add(ipc_client_list, client); |
185 | 178 | ||
186 | return 0; | 179 | return 0; |
@@ -248,8 +241,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) { | |||
248 | return 0; | 241 | return 0; |
249 | } | 242 | } |
250 | 243 | ||
251 | void ipc_client_disconnect(struct ipc_client *client) | 244 | void ipc_client_disconnect(struct ipc_client *client) { |
252 | { | ||
253 | if (!sway_assert(client != NULL, "client != NULL")) { | 245 | if (!sway_assert(client != NULL, "client != NULL")) { |
254 | return; | 246 | return; |
255 | } | 247 | } |
@@ -333,8 +325,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
333 | ipc_client_disconnect(client); | 325 | ipc_client_disconnect(client); |
334 | return; | 326 | return; |
335 | } | 327 | } |
336 | if (client->payload_length > 0) | 328 | if (client->payload_length > 0) { |
337 | { | ||
338 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); | 329 | ssize_t received = recv(client->fd, buf, client->payload_length, 0); |
339 | if (received == -1) | 330 | if (received == -1) |
340 | { | 331 | { |
@@ -351,7 +342,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
351 | switch (client->current_command) { | 342 | switch (client->current_command) { |
352 | case IPC_COMMAND: | 343 | case IPC_COMMAND: |
353 | { | 344 | { |
354 | if (!(config->ipc_policy & IPC_FEATURE_COMMAND)) { | 345 | if (!(client->security_policy & IPC_FEATURE_COMMAND)) { |
355 | goto exit_denied; | 346 | goto exit_denied; |
356 | } | 347 | } |
357 | struct cmd_results *results = handle_command(buf, CONTEXT_IPC); | 348 | struct cmd_results *results = handle_command(buf, CONTEXT_IPC); |
@@ -365,6 +356,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
365 | 356 | ||
366 | case IPC_SUBSCRIBE: | 357 | case IPC_SUBSCRIBE: |
367 | { | 358 | { |
359 | // TODO: Check if they're permitted to use these events | ||
368 | struct json_object *request = json_tokener_parse(buf); | 360 | struct json_object *request = json_tokener_parse(buf); |
369 | if (request == NULL) { | 361 | if (request == NULL) { |
370 | ipc_send_reply(client, "{\"success\": false}", 18); | 362 | ipc_send_reply(client, "{\"success\": false}", 18); |
@@ -403,7 +395,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
403 | 395 | ||
404 | case IPC_GET_WORKSPACES: | 396 | case IPC_GET_WORKSPACES: |
405 | { | 397 | { |
406 | if (!(config->ipc_policy & IPC_FEATURE_GET_WORKSPACES)) { | 398 | if (!(client->security_policy & IPC_FEATURE_GET_WORKSPACES)) { |
407 | goto exit_denied; | 399 | goto exit_denied; |
408 | } | 400 | } |
409 | json_object *workspaces = json_object_new_array(); | 401 | json_object *workspaces = json_object_new_array(); |
@@ -416,7 +408,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
416 | 408 | ||
417 | case IPC_GET_INPUTS: | 409 | case IPC_GET_INPUTS: |
418 | { | 410 | { |
419 | if (!(config->ipc_policy & IPC_FEATURE_GET_INPUTS)) { | 411 | if (!(client->security_policy & IPC_FEATURE_GET_INPUTS)) { |
420 | goto exit_denied; | 412 | goto exit_denied; |
421 | } | 413 | } |
422 | json_object *inputs = json_object_new_array(); | 414 | json_object *inputs = json_object_new_array(); |
@@ -442,7 +434,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
442 | 434 | ||
443 | case IPC_GET_OUTPUTS: | 435 | case IPC_GET_OUTPUTS: |
444 | { | 436 | { |
445 | if (!(config->ipc_policy & IPC_FEATURE_GET_OUTPUTS)) { | 437 | if (!(client->security_policy & IPC_FEATURE_GET_OUTPUTS)) { |
446 | goto exit_denied; | 438 | goto exit_denied; |
447 | } | 439 | } |
448 | json_object *outputs = json_object_new_array(); | 440 | json_object *outputs = json_object_new_array(); |
@@ -455,7 +447,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
455 | 447 | ||
456 | case IPC_GET_TREE: | 448 | case IPC_GET_TREE: |
457 | { | 449 | { |
458 | if (!(config->ipc_policy & IPC_FEATURE_GET_TREE)) { | 450 | if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { |
459 | goto exit_denied; | 451 | goto exit_denied; |
460 | } | 452 | } |
461 | json_object *tree = ipc_json_describe_container_recursive(&root_container); | 453 | json_object *tree = ipc_json_describe_container_recursive(&root_container); |
@@ -522,7 +514,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
522 | 514 | ||
523 | case IPC_GET_BAR_CONFIG: | 515 | case IPC_GET_BAR_CONFIG: |
524 | { | 516 | { |
525 | if (!(config->ipc_policy & IPC_FEATURE_GET_BAR_CONFIG)) { | 517 | if (!(client->security_policy & IPC_FEATURE_GET_BAR_CONFIG)) { |
526 | goto exit_denied; | 518 | goto exit_denied; |
527 | } | 519 | } |
528 | if (!buf[0]) { | 520 | if (!buf[0]) { |
@@ -567,6 +559,7 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
567 | 559 | ||
568 | exit_denied: | 560 | exit_denied: |
569 | ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); | 561 | ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); |
562 | sway_log(L_DEBUG, "Denied IPC client access to %i", client->current_command); | ||
570 | 563 | ||
571 | exit_cleanup: | 564 | exit_cleanup: |
572 | client->payload_length = 0; | 565 | client->payload_length = 0; |
@@ -594,6 +587,8 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay | |||
594 | return false; | 587 | return false; |
595 | } | 588 | } |
596 | 589 | ||
590 | sway_log(L_DEBUG, "Send IPC reply: %s", payload); | ||
591 | |||
597 | return true; | 592 | return true; |
598 | } | 593 | } |
599 | 594 | ||
@@ -616,10 +611,33 @@ void ipc_get_outputs_callback(swayc_t *container, void *data) { | |||
616 | } | 611 | } |
617 | 612 | ||
618 | void ipc_send_event(const char *json_string, enum ipc_command_type event) { | 613 | void ipc_send_event(const char *json_string, enum ipc_command_type event) { |
614 | static struct { | ||
615 | enum ipc_command_type event; | ||
616 | enum ipc_feature feature; | ||
617 | } security_mappings[] = { | ||
618 | { IPC_EVENT_WORKSPACE, IPC_FEATURE_EVENT_WORKSPACE }, | ||
619 | { IPC_EVENT_OUTPUT, IPC_FEATURE_EVENT_OUTPUT }, | ||
620 | { IPC_EVENT_MODE, IPC_FEATURE_EVENT_MODE }, | ||
621 | { IPC_EVENT_WINDOW, IPC_FEATURE_EVENT_WINDOW }, | ||
622 | { IPC_EVENT_BINDING, IPC_FEATURE_EVENT_BINDING }, | ||
623 | { IPC_EVENT_INPUT, IPC_FEATURE_EVENT_INPUT } | ||
624 | }; | ||
625 | |||
626 | uint32_t security_mask = 0; | ||
627 | for (size_t i = 0; i < sizeof(security_mappings) / sizeof(security_mappings[0]); ++i) { | ||
628 | if (security_mappings[i].event == event) { | ||
629 | security_mask = security_mappings[i].feature; | ||
630 | break; | ||
631 | } | ||
632 | } | ||
633 | |||
619 | int i; | 634 | int i; |
620 | struct ipc_client *client; | 635 | struct ipc_client *client; |
621 | for (i = 0; i < ipc_client_list->length; i++) { | 636 | for (i = 0; i < ipc_client_list->length; i++) { |
622 | client = ipc_client_list->items[i]; | 637 | client = ipc_client_list->items[i]; |
638 | if (!(client->security_policy & security_mask)) { | ||
639 | continue; | ||
640 | } | ||
623 | if ((client->subscribed_events & event_mask(event)) == 0) { | 641 | if ((client->subscribed_events & event_mask(event)) == 0) { |
624 | continue; | 642 | continue; |
625 | } | 643 | } |
@@ -632,9 +650,6 @@ void ipc_send_event(const char *json_string, enum ipc_command_type event) { | |||
632 | } | 650 | } |
633 | 651 | ||
634 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | 652 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { |
635 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WORKSPACE)) { | ||
636 | return; | ||
637 | } | ||
638 | sway_log(L_DEBUG, "Sending workspace::%s event", change); | 653 | sway_log(L_DEBUG, "Sending workspace::%s event", change); |
639 | json_object *obj = json_object_new_object(); | 654 | json_object *obj = json_object_new_object(); |
640 | json_object_object_add(obj, "change", json_object_new_string(change)); | 655 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -659,9 +674,6 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | |||
659 | } | 674 | } |
660 | 675 | ||
661 | void ipc_event_window(swayc_t *window, const char *change) { | 676 | void ipc_event_window(swayc_t *window, const char *change) { |
662 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WINDOW)) { | ||
663 | return; | ||
664 | } | ||
665 | sway_log(L_DEBUG, "Sending window::%s event", change); | 677 | sway_log(L_DEBUG, "Sending window::%s event", change); |
666 | json_object *obj = json_object_new_object(); | 678 | json_object *obj = json_object_new_object(); |
667 | json_object_object_add(obj, "change", json_object_new_string(change)); | 679 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -687,9 +699,6 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
687 | } | 699 | } |
688 | 700 | ||
689 | void ipc_event_mode(const char *mode) { | 701 | void ipc_event_mode(const char *mode) { |
690 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_MODE)) { | ||
691 | return; | ||
692 | } | ||
693 | sway_log(L_DEBUG, "Sending mode::%s event", mode); | 702 | sway_log(L_DEBUG, "Sending mode::%s event", mode); |
694 | json_object *obj = json_object_new_object(); | 703 | json_object *obj = json_object_new_object(); |
695 | json_object_object_add(obj, "change", json_object_new_string(mode)); | 704 | json_object_object_add(obj, "change", json_object_new_string(mode)); |
@@ -715,9 +724,6 @@ void ipc_event_modifier(uint32_t modifier, const char *state) { | |||
715 | } | 724 | } |
716 | 725 | ||
717 | static void ipc_event_binding(json_object *sb_obj) { | 726 | static void ipc_event_binding(json_object *sb_obj) { |
718 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_BINDING)) { | ||
719 | return; | ||
720 | } | ||
721 | sway_log(L_DEBUG, "Sending binding::run event"); | 727 | sway_log(L_DEBUG, "Sending binding::run event"); |
722 | json_object *obj = json_object_new_object(); | 728 | json_object *obj = json_object_new_object(); |
723 | json_object_object_add(obj, "change", json_object_new_string("run")); | 729 | json_object_object_add(obj, "change", json_object_new_string("run")); |