diff options
Diffstat (limited to 'sway/ipc-server.c')
-rw-r--r-- | sway/ipc-server.c | 66 |
1 files changed, 57 insertions, 9 deletions
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index ebb5ce58..c04c465a 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <libinput.h> | 15 | #include <libinput.h> |
16 | #include "sway/ipc-json.h" | 16 | #include "sway/ipc-json.h" |
17 | #include "sway/ipc-server.h" | 17 | #include "sway/ipc-server.h" |
18 | #include "sway/security.h" | ||
18 | #include "sway/config.h" | 19 | #include "sway/config.h" |
19 | #include "sway/commands.h" | 20 | #include "sway/commands.h" |
20 | #include "sway/input.h" | 21 | #include "sway/input.h" |
@@ -55,8 +56,6 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay | |||
55 | void ipc_get_workspaces_callback(swayc_t *workspace, void *data); | 56 | void ipc_get_workspaces_callback(swayc_t *workspace, void *data); |
56 | void ipc_get_outputs_callback(swayc_t *container, void *data); | 57 | void ipc_get_outputs_callback(swayc_t *container, void *data); |
57 | 58 | ||
58 | #define event_mask(ev) (1 << (ev & 0x7F)) | ||
59 | |||
60 | void ipc_init(void) { | 59 | void ipc_init(void) { |
61 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); | 60 | ipc_socket = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); |
62 | if (ipc_socket == -1) { | 61 | if (ipc_socket == -1) { |
@@ -126,6 +125,17 @@ struct sockaddr_un *ipc_user_sockaddr(void) { | |||
126 | return ipc_sockaddr; | 125 | return ipc_sockaddr; |
127 | } | 126 | } |
128 | 127 | ||
128 | static pid_t get_client_pid(int client_fd) { | ||
129 | struct ucred ucred; | ||
130 | socklen_t len = sizeof(struct ucred); | ||
131 | |||
132 | if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) { | ||
133 | return -1; | ||
134 | } | ||
135 | |||
136 | return ucred.pid; | ||
137 | } | ||
138 | |||
129 | int ipc_handle_connection(int fd, uint32_t mask, void *data) { | 139 | int ipc_handle_connection(int fd, uint32_t mask, void *data) { |
130 | (void) fd; (void) data; | 140 | (void) fd; (void) data; |
131 | sway_log(L_DEBUG, "Event on IPC listening socket"); | 141 | sway_log(L_DEBUG, "Event on IPC listening socket"); |
@@ -144,6 +154,15 @@ int ipc_handle_connection(int fd, uint32_t mask, void *data) { | |||
144 | return 0; | 154 | return 0; |
145 | } | 155 | } |
146 | 156 | ||
157 | pid_t pid = get_client_pid(client_fd); | ||
158 | if (!(get_feature_policy(pid) & FEATURE_IPC)) { | ||
159 | sway_log(L_INFO, "Permission to connect to IPC socket denied to %d", pid); | ||
160 | const char *error = "{\"success\": false, \"message\": \"Permission denied\"}"; | ||
161 | write(client_fd, &error, sizeof(error)); | ||
162 | close(client_fd); | ||
163 | return 0; | ||
164 | } | ||
165 | |||
147 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); | 166 | struct ipc_client* client = malloc(sizeof(struct ipc_client)); |
148 | client->payload_length = 0; | 167 | client->payload_length = 0; |
149 | client->fd = client_fd; | 168 | client->fd = client_fd; |
@@ -309,10 +328,15 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
309 | } | 328 | } |
310 | buf[client->payload_length] = '\0'; | 329 | buf[client->payload_length] = '\0'; |
311 | 330 | ||
331 | const char *error_denied = "{ \"success\": false, \"error\": \"Permission denied\" }"; | ||
332 | |||
312 | switch (client->current_command) { | 333 | switch (client->current_command) { |
313 | case IPC_COMMAND: | 334 | case IPC_COMMAND: |
314 | { | 335 | { |
315 | struct cmd_results *results = handle_command(buf); | 336 | if (!(config->ipc_policy & IPC_FEATURE_COMMAND)) { |
337 | goto exit_denied; | ||
338 | } | ||
339 | struct cmd_results *results = handle_command(buf, CONTEXT_IPC); | ||
316 | const char *json = cmd_results_to_json(results); | 340 | const char *json = cmd_results_to_json(results); |
317 | char reply[256]; | 341 | char reply[256]; |
318 | int length = snprintf(reply, sizeof(reply), "%s", json); | 342 | int length = snprintf(reply, sizeof(reply), "%s", json); |
@@ -343,10 +367,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
343 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); | 367 | client->subscribed_events |= event_mask(IPC_EVENT_WINDOW); |
344 | } else if (strcmp(event_type, "modifier") == 0) { | 368 | } else if (strcmp(event_type, "modifier") == 0) { |
345 | client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); | 369 | client->subscribed_events |= event_mask(IPC_EVENT_MODIFIER); |
346 | #if SWAY_BINDING_EVENT | ||
347 | } else if (strcmp(event_type, "binding") == 0) { | 370 | } else if (strcmp(event_type, "binding") == 0) { |
348 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); | 371 | client->subscribed_events |= event_mask(IPC_EVENT_BINDING); |
349 | #endif | ||
350 | } else { | 372 | } else { |
351 | ipc_send_reply(client, "{\"success\": false}", 18); | 373 | ipc_send_reply(client, "{\"success\": false}", 18); |
352 | json_object_put(request); | 374 | json_object_put(request); |
@@ -363,6 +385,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
363 | 385 | ||
364 | case IPC_GET_WORKSPACES: | 386 | case IPC_GET_WORKSPACES: |
365 | { | 387 | { |
388 | if (!(config->ipc_policy & IPC_FEATURE_GET_WORKSPACES)) { | ||
389 | goto exit_denied; | ||
390 | } | ||
366 | json_object *workspaces = json_object_new_array(); | 391 | json_object *workspaces = json_object_new_array(); |
367 | container_map(&root_container, ipc_get_workspaces_callback, workspaces); | 392 | container_map(&root_container, ipc_get_workspaces_callback, workspaces); |
368 | const char *json_string = json_object_to_json_string(workspaces); | 393 | const char *json_string = json_object_to_json_string(workspaces); |
@@ -373,6 +398,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
373 | 398 | ||
374 | case IPC_GET_INPUTS: | 399 | case IPC_GET_INPUTS: |
375 | { | 400 | { |
401 | if (!(config->ipc_policy & IPC_FEATURE_GET_INPUTS)) { | ||
402 | goto exit_denied; | ||
403 | } | ||
376 | json_object *inputs = json_object_new_array(); | 404 | json_object *inputs = json_object_new_array(); |
377 | if (input_devices) { | 405 | if (input_devices) { |
378 | for(int i=0; i<input_devices->length; i++) { | 406 | for(int i=0; i<input_devices->length; i++) { |
@@ -392,6 +420,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
392 | 420 | ||
393 | case IPC_GET_OUTPUTS: | 421 | case IPC_GET_OUTPUTS: |
394 | { | 422 | { |
423 | if (!(config->ipc_policy & IPC_FEATURE_GET_OUTPUTS)) { | ||
424 | goto exit_denied; | ||
425 | } | ||
395 | json_object *outputs = json_object_new_array(); | 426 | json_object *outputs = json_object_new_array(); |
396 | container_map(&root_container, ipc_get_outputs_callback, outputs); | 427 | container_map(&root_container, ipc_get_outputs_callback, outputs); |
397 | const char *json_string = json_object_to_json_string(outputs); | 428 | const char *json_string = json_object_to_json_string(outputs); |
@@ -402,6 +433,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
402 | 433 | ||
403 | case IPC_GET_TREE: | 434 | case IPC_GET_TREE: |
404 | { | 435 | { |
436 | if (!(config->ipc_policy & IPC_FEATURE_GET_TREE)) { | ||
437 | goto exit_denied; | ||
438 | } | ||
405 | json_object *tree = ipc_json_describe_container_recursive(&root_container); | 439 | json_object *tree = ipc_json_describe_container_recursive(&root_container); |
406 | const char *json_string = json_object_to_json_string(tree); | 440 | const char *json_string = json_object_to_json_string(tree); |
407 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); | 441 | ipc_send_reply(client, json_string, (uint32_t) strlen(json_string)); |
@@ -462,6 +496,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
462 | 496 | ||
463 | case IPC_GET_BAR_CONFIG: | 497 | case IPC_GET_BAR_CONFIG: |
464 | { | 498 | { |
499 | if (!(config->ipc_policy & IPC_FEATURE_GET_BAR_CONFIG)) { | ||
500 | goto exit_denied; | ||
501 | } | ||
465 | if (!buf[0]) { | 502 | if (!buf[0]) { |
466 | // Send list of configured bar IDs | 503 | // Send list of configured bar IDs |
467 | json_object *bars = json_object_new_array(); | 504 | json_object *bars = json_object_new_array(); |
@@ -502,6 +539,9 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
502 | goto exit_cleanup; | 539 | goto exit_cleanup; |
503 | } | 540 | } |
504 | 541 | ||
542 | exit_denied: | ||
543 | ipc_send_reply(client, error_denied, (uint32_t)strlen(error_denied)); | ||
544 | |||
505 | exit_cleanup: | 545 | exit_cleanup: |
506 | client->payload_length = 0; | 546 | client->payload_length = 0; |
507 | free(buf); | 547 | free(buf); |
@@ -566,6 +606,9 @@ void ipc_send_event(const char *json_string, enum ipc_command_type event) { | |||
566 | } | 606 | } |
567 | 607 | ||
568 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | 608 | void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { |
609 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WORKSPACE)) { | ||
610 | return; | ||
611 | } | ||
569 | sway_log(L_DEBUG, "Sending workspace::%s event", change); | 612 | sway_log(L_DEBUG, "Sending workspace::%s event", change); |
570 | json_object *obj = json_object_new_object(); | 613 | json_object *obj = json_object_new_object(); |
571 | json_object_object_add(obj, "change", json_object_new_string(change)); | 614 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -590,6 +633,9 @@ void ipc_event_workspace(swayc_t *old, swayc_t *new, const char *change) { | |||
590 | } | 633 | } |
591 | 634 | ||
592 | void ipc_event_window(swayc_t *window, const char *change) { | 635 | void ipc_event_window(swayc_t *window, const char *change) { |
636 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_WINDOW)) { | ||
637 | return; | ||
638 | } | ||
593 | sway_log(L_DEBUG, "Sending window::%s event", change); | 639 | sway_log(L_DEBUG, "Sending window::%s event", change); |
594 | json_object *obj = json_object_new_object(); | 640 | json_object *obj = json_object_new_object(); |
595 | json_object_object_add(obj, "change", json_object_new_string(change)); | 641 | json_object_object_add(obj, "change", json_object_new_string(change)); |
@@ -615,6 +661,9 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
615 | } | 661 | } |
616 | 662 | ||
617 | void ipc_event_mode(const char *mode) { | 663 | void ipc_event_mode(const char *mode) { |
664 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_MODE)) { | ||
665 | return; | ||
666 | } | ||
618 | sway_log(L_DEBUG, "Sending mode::%s event", mode); | 667 | sway_log(L_DEBUG, "Sending mode::%s event", mode); |
619 | json_object *obj = json_object_new_object(); | 668 | json_object *obj = json_object_new_object(); |
620 | json_object_object_add(obj, "change", json_object_new_string(mode)); | 669 | json_object_object_add(obj, "change", json_object_new_string(mode)); |
@@ -639,8 +688,10 @@ void ipc_event_modifier(uint32_t modifier, const char *state) { | |||
639 | json_object_put(obj); // free | 688 | json_object_put(obj); // free |
640 | } | 689 | } |
641 | 690 | ||
642 | #if SWAY_BINDING_EVENT | ||
643 | static void ipc_event_binding(json_object *sb_obj) { | 691 | static void ipc_event_binding(json_object *sb_obj) { |
692 | if (!(config->ipc_policy & IPC_FEATURE_EVENT_BINDING)) { | ||
693 | return; | ||
694 | } | ||
644 | sway_log(L_DEBUG, "Sending binding::run event"); | 695 | sway_log(L_DEBUG, "Sending binding::run event"); |
645 | json_object *obj = json_object_new_object(); | 696 | json_object *obj = json_object_new_object(); |
646 | json_object_object_add(obj, "change", json_object_new_string("run")); | 697 | json_object_object_add(obj, "change", json_object_new_string("run")); |
@@ -651,10 +702,8 @@ static void ipc_event_binding(json_object *sb_obj) { | |||
651 | 702 | ||
652 | json_object_put(obj); // free | 703 | json_object_put(obj); // free |
653 | } | 704 | } |
654 | #endif | ||
655 | 705 | ||
656 | void ipc_event_binding_keyboard(struct sway_binding *sb) { | 706 | void ipc_event_binding_keyboard(struct sway_binding *sb) { |
657 | #if SWAY_BINDING_EVENT | ||
658 | json_object *sb_obj = json_object_new_object(); | 707 | json_object *sb_obj = json_object_new_object(); |
659 | json_object_object_add(sb_obj, "command", json_object_new_string(sb->command)); | 708 | json_object_object_add(sb_obj, "command", json_object_new_string(sb->command)); |
660 | 709 | ||
@@ -705,5 +754,4 @@ void ipc_event_binding_keyboard(struct sway_binding *sb) { | |||
705 | json_object_object_add(sb_obj, "input_type", json_object_new_string("keyboard")); | 754 | json_object_object_add(sb_obj, "input_type", json_object_new_string("keyboard")); |
706 | 755 | ||
707 | ipc_event_binding(sb_obj); | 756 | ipc_event_binding(sb_obj); |
708 | #endif | ||
709 | } | 757 | } |