summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Drew DeVault <sir@cmpwn.com>2017-02-20 07:42:08 -0500
committerLibravatar Drew DeVault <sir@cmpwn.com>2017-02-20 07:51:31 -0500
commit126ce571dab09d84d8ee1b760981dbba7cbc1000 (patch)
treec13e957c752e3ae0798945e2e0be2af99da7dc68
parentAdd * policies and fix bug (diff)
downloadsway-126ce571dab09d84d8ee1b760981dbba7cbc1000.tar.gz
sway-126ce571dab09d84d8ee1b760981dbba7cbc1000.tar.zst
sway-126ce571dab09d84d8ee1b760981dbba7cbc1000.zip
Read configs from /etc/sway/security.d/*
-rw-r--r--include/sway/config.h2
-rw-r--r--security.d/00-defaults.in5
-rw-r--r--sway/commands/commands.c8
-rw-r--r--sway/commands/ipc.c8
-rw-r--r--sway/commands/permit.c20
-rw-r--r--sway/config.c52
-rw-r--r--sway/ipc-server.c15
-rw-r--r--sway/main.c7
-rw-r--r--sway/sway-security.7.txt2
9 files changed, 77 insertions, 42 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index ba49b9a0..d77fbd51 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -340,6 +340,8 @@ void free_config(struct sway_config *config);
340 */ 340 */
341char *do_var_replacement(char *str); 341char *do_var_replacement(char *str);
342 342
343struct cmd_results *check_security_config();
344
343int input_identifier_cmp(const void *item, const void *data); 345int input_identifier_cmp(const void *item, const void *data);
344void merge_input_config(struct input_config *dst, struct input_config *src); 346void merge_input_config(struct input_config *dst, struct input_config *src);
345void apply_input_config(struct input_config *ic, struct libinput_device *dev); 347void apply_input_config(struct input_config *ic, struct libinput_device *dev);
diff --git a/security.d/00-defaults.in b/security.d/00-defaults.in
index 99859edd..f319e446 100644
--- a/security.d/00-defaults.in
+++ b/security.d/00-defaults.in
@@ -29,6 +29,11 @@ ipc __PREFIX__/bin/swaybar {
29 outputs enabled 29 outputs enabled
30 workspaces enabled 30 workspaces enabled
31 command enabled 31 command enabled
32
33 events {
34 workspace enabled
35 mode enabled
36 }
32} 37}
33 38
34ipc __PREFIX__/bin/swaygrab { 39ipc __PREFIX__/bin/swaygrab {
diff --git a/sway/commands/commands.c b/sway/commands/commands.c
index 8c7ed487..0c64970c 100644
--- a/sway/commands/commands.c
+++ b/sway/commands/commands.c
@@ -10,6 +10,9 @@ struct cmd_results *cmd_commands(int argc, char **argv) {
10 if ((error = checkarg(argc, "commands", EXPECTED_EQUAL_TO, 1))) { 10 if ((error = checkarg(argc, "commands", EXPECTED_EQUAL_TO, 1))) {
11 return error; 11 return error;
12 } 12 }
13 if ((error = check_security_config())) {
14 return error;
15 }
13 16
14 if (strcmp(argv[0], "{") != 0) { 17 if (strcmp(argv[0], "{") != 0) {
15 return cmd_results_new(CMD_FAILURE, "commands", "Expected block declaration"); 18 return cmd_results_new(CMD_FAILURE, "commands", "Expected block declaration");
@@ -19,10 +22,5 @@ struct cmd_results *cmd_commands(int argc, char **argv) {
19 return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file."); 22 return cmd_results_new(CMD_FAILURE, "commands", "Can only be used in config file.");
20 } 23 }
21 24
22 if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
23 return cmd_results_new(CMD_INVALID, "permit",
24 "This command is only permitted to run from " SYSCONFDIR "/sway/security");
25 }
26
27 return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL); 25 return cmd_results_new(CMD_BLOCK_COMMANDS, NULL, NULL);
28} 26}
diff --git a/sway/commands/ipc.c b/sway/commands/ipc.c
index d49aab64..8a7b849f 100644
--- a/sway/commands/ipc.c
+++ b/sway/commands/ipc.c
@@ -14,6 +14,9 @@ struct cmd_results *cmd_ipc(int argc, char **argv) {
14 if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 2))) { 14 if ((error = checkarg(argc, "ipc", EXPECTED_EQUAL_TO, 2))) {
15 return error; 15 return error;
16 } 16 }
17 if ((error = check_security_config())) {
18 return error;
19 }
17 20
18 const char *program = argv[0]; 21 const char *program = argv[0];
19 22
@@ -26,11 +29,6 @@ struct cmd_results *cmd_ipc(int argc, char **argv) {
26 return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file."); 29 return cmd_results_new(CMD_FAILURE, "ipc", "Can only be used in config file.");
27 } 30 }
28 31
29 if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) {
30 return cmd_results_new(CMD_INVALID, "permit",
31 "This command is only permitted to run from " SYSCONFDIR "/sway/security");
32 }
33
34 current_policy = alloc_ipc_policy(program); 32 current_policy = alloc_ipc_policy(program);
35 list_add(config->ipc_policies, current_policy); 33 list_add(config->ipc_policies, current_policy);
36 34
diff --git a/sway/commands/permit.c b/sway/commands/permit.c
index 6eb71816..e2bec2e2 100644
--- a/sway/commands/permit.c
+++ b/sway/commands/permit.c
@@ -62,19 +62,13 @@ struct cmd_results *cmd_permit(int argc, char **argv) {
62 if ((error = checkarg(argc, "permit", EXPECTED_MORE_THAN, 1))) { 62 if ((error = checkarg(argc, "permit", EXPECTED_MORE_THAN, 1))) {
63 return error; 63 return error;
64 } 64 }
65 65 if ((error = check_security_config())) {
66 if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) { 66 return error;
67 return cmd_results_new(CMD_INVALID, "permit",
68 "This command is only permitted to run from " SYSCONFDIR "/sway/security");
69 } 67 }
70 68
71 struct feature_policy *policy = get_policy(argv[0]); 69 struct feature_policy *policy = get_policy(argv[0]);
72 policy->features |= get_features(argc, argv, &error); 70 policy->features |= get_features(argc, argv, &error);
73 71
74 if (error) {
75 return error;
76 }
77
78 sway_log(L_DEBUG, "Permissions granted to %s for features %d", 72 sway_log(L_DEBUG, "Permissions granted to %s for features %d",
79 policy->program, policy->features); 73 policy->program, policy->features);
80 74
@@ -86,19 +80,13 @@ struct cmd_results *cmd_reject(int argc, char **argv) {
86 if ((error = checkarg(argc, "reject", EXPECTED_MORE_THAN, 1))) { 80 if ((error = checkarg(argc, "reject", EXPECTED_MORE_THAN, 1))) {
87 return error; 81 return error;
88 } 82 }
89 83 if ((error = check_security_config())) {
90 if (!current_config_path || strcmp(SYSCONFDIR "/sway/security", current_config_path) != 0) { 84 return error;
91 return cmd_results_new(CMD_INVALID, "permit",
92 "This command is only permitted to run from " SYSCONFDIR "/sway/security");
93 } 85 }
94 86
95 struct feature_policy *policy = get_policy(argv[0]); 87 struct feature_policy *policy = get_policy(argv[0]);
96 policy->features &= ~get_features(argc, argv, &error); 88 policy->features &= ~get_features(argc, argv, &error);
97 89
98 if (error) {
99 return error;
100 }
101
102 sway_log(L_DEBUG, "Permissions granted to %s for features %d", 90 sway_log(L_DEBUG, "Permissions granted to %s for features %d",
103 policy->program, policy->features); 91 policy->program, policy->features);
104 92
diff --git a/sway/config.c b/sway/config.c
index 4a3c953d..88e6fad1 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -11,6 +11,7 @@
11#include <libinput.h> 11#include <libinput.h>
12#include <limits.h> 12#include <limits.h>
13#include <float.h> 13#include <float.h>
14#include <dirent.h>
14#include "wayland-desktop-shell-server-protocol.h" 15#include "wayland-desktop-shell-server-protocol.h"
15#include "sway/commands.h" 16#include "sway/commands.h"
16#include "sway/config.h" 17#include "sway/config.h"
@@ -485,6 +486,10 @@ static bool load_config(const char *path, struct sway_config *config) {
485 return true; 486 return true;
486} 487}
487 488
489static int qstrcmp(const void* a, const void* b) {
490 return strcmp(*((char**) a), *((char**) b));
491}
492
488bool load_main_config(const char *file, bool is_active) { 493bool load_main_config(const char *file, bool is_active) {
489 input_init(); 494 input_init();
490 495
@@ -512,7 +517,43 @@ bool load_main_config(const char *file, bool is_active) {
512 list_add(config->config_chain, path); 517 list_add(config->config_chain, path);
513 518
514 config->reading = true; 519 config->reading = true;
515 bool success = load_config(SYSCONFDIR "/sway/security", config); 520
521 // Read security configs
522 bool success = true;
523 DIR *dir = opendir(SYSCONFDIR "/sway/security.d");
524 if (!dir) {
525 sway_log(L_ERROR, "%s does not exist, sway will have no security configuration"
526 " and will probably be broken", SYSCONFDIR "/sway/security.d");
527 } else {
528 list_t *secconfigs = create_list();
529 char *base = SYSCONFDIR "/sway/security.d/";
530 struct dirent *ent = readdir(dir);
531 while (ent != NULL) {
532 if (ent->d_type == DT_REG) {
533 char *_path = malloc(strlen(ent->d_name) + strlen(base) + 1);
534 strcpy(_path, base);
535 strcat(_path, ent->d_name);
536 list_add(secconfigs, _path);
537 }
538 ent = readdir(dir);
539 }
540 closedir(dir);
541
542 list_qsort(secconfigs, qstrcmp);
543 for (int i = 0; i < secconfigs->length; ++i) {
544 char *_path = secconfigs->items[i];
545 struct stat s;
546 if (stat(_path, &s) || s.st_uid != 0 || s.st_gid != 0 || (s.st_mode & 0777) != 0644) {
547 sway_log(L_ERROR, "Refusing to load %s - it must be owned by root and mode 644", _path);
548 success = false;
549 } else {
550 success = success && load_config(_path, config);
551 }
552 }
553
554 free_flat_list(secconfigs);
555 }
556
516 success = success && load_config(path, config); 557 success = success && load_config(path, config);
517 558
518 if (is_active) { 559 if (is_active) {
@@ -620,6 +661,15 @@ bool load_include_configs(const char *path, struct sway_config *config) {
620 return true; 661 return true;
621} 662}
622 663
664struct cmd_results *check_security_config() {
665 if (!current_config_path || strncmp(SYSCONFDIR "/sway/security.d/", current_config_path,
666 strlen(SYSCONFDIR "/sway/security.d/")) != 0) {
667 return cmd_results_new(CMD_INVALID, "permit",
668 "This command is only permitted to run from " SYSCONFDIR "/sway/security.d/*");
669 }
670 return NULL;
671}
672
623bool read_config(FILE *file, struct sway_config *config) { 673bool read_config(FILE *file, struct sway_config *config) {
624 bool success = true; 674 bool success = true;
625 enum cmd_status block = CMD_BLOCK_END; 675 enum cmd_status block = CMD_BLOCK_END;
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index 20a19b44..eddae461 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -241,8 +241,7 @@ int ipc_client_handle_readable(int client_fd, uint32_t mask, void *data) {
241 return 0; 241 return 0;
242} 242}
243 243
244void ipc_client_disconnect(struct ipc_client *client) 244void ipc_client_disconnect(struct ipc_client *client) {
245{
246 if (!sway_assert(client != NULL, "client != NULL")) { 245 if (!sway_assert(client != NULL, "client != NULL")) {
247 return; 246 return;
248 } 247 }
@@ -326,8 +325,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
326 ipc_client_disconnect(client); 325 ipc_client_disconnect(client);
327 return; 326 return;
328 } 327 }
329 if (client->payload_length > 0) 328 if (client->payload_length > 0) {
330 {
331 ssize_t received = recv(client->fd, buf, client->payload_length, 0); 329 ssize_t received = recv(client->fd, buf, client->payload_length, 0);
332 if (received == -1) 330 if (received == -1)
333 { 331 {
@@ -397,7 +395,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
397 395
398 case IPC_GET_WORKSPACES: 396 case IPC_GET_WORKSPACES:
399 { 397 {
400 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { 398 if (!(client->security_policy & IPC_FEATURE_GET_WORKSPACES)) {
401 goto exit_denied; 399 goto exit_denied;
402 } 400 }
403 json_object *workspaces = json_object_new_array(); 401 json_object *workspaces = json_object_new_array();
@@ -410,7 +408,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
410 408
411 case IPC_GET_INPUTS: 409 case IPC_GET_INPUTS:
412 { 410 {
413 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { 411 if (!(client->security_policy & IPC_FEATURE_GET_INPUTS)) {
414 goto exit_denied; 412 goto exit_denied;
415 } 413 }
416 json_object *inputs = json_object_new_array(); 414 json_object *inputs = json_object_new_array();
@@ -436,7 +434,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
436 434
437 case IPC_GET_OUTPUTS: 435 case IPC_GET_OUTPUTS:
438 { 436 {
439 if (!(client->security_policy & IPC_FEATURE_GET_TREE)) { 437 if (!(client->security_policy & IPC_FEATURE_GET_OUTPUTS)) {
440 goto exit_denied; 438 goto exit_denied;
441 } 439 }
442 json_object *outputs = json_object_new_array(); 440 json_object *outputs = json_object_new_array();
@@ -561,6 +559,7 @@ void ipc_client_handle_command(struct ipc_client *client) {
561 559
562exit_denied: 560exit_denied:
563 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);
564 563
565exit_cleanup: 564exit_cleanup:
566 client->payload_length = 0; 565 client->payload_length = 0;
@@ -588,6 +587,8 @@ bool ipc_send_reply(struct ipc_client *client, const char *payload, uint32_t pay
588 return false; 587 return false;
589 } 588 }
590 589
590 sway_log(L_DEBUG, "Send IPC reply: %s", payload);
591
591 return true; 592 return true;
592} 593}
593 594
diff --git a/sway/main.c b/sway/main.c
index 1c4c56c0..0151e078 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -175,13 +175,6 @@ static void security_sanity_check() {
175 cap_free(cap); 175 cap_free(cap);
176 } 176 }
177#endif 177#endif
178 if (!stat(SYSCONFDIR "/sway", &s)) {
179 if (s.st_uid != 0 || s.st_gid != 0
180 || (s.st_mode & S_IWGRP) || (s.st_mode & S_IWOTH)) {
181 sway_log(L_ERROR,
182 "!! DANGER !! " SYSCONFDIR "/sway is not secure! It should be owned by root and set to 0755 at the minimum");
183 }
184 }
185} 178}
186 179
187int main(int argc, char **argv) { 180int main(int argc, char **argv) {
diff --git a/sway/sway-security.7.txt b/sway/sway-security.7.txt
index 98e3f5ac..fb47ffcf 100644
--- a/sway/sway-security.7.txt
+++ b/sway/sway-security.7.txt
@@ -21,7 +21,7 @@ you must make a few changes external to sway first.
21 21
22Configuration of security features is limited to files in the security directory 22Configuration of security features is limited to files in the security directory
23(this is likely /etc/sway/security.d/*, but depends on your installation prefix). 23(this is likely /etc/sway/security.d/*, but depends on your installation prefix).
24Files in this directory must be owned by root:root and chmod 600. The default 24Files in this directory must be owned by root:root and chmod 644. The default
25security configuration is installed to /etc/sway/security.d/00-defaults, and 25security configuration is installed to /etc/sway/security.d/00-defaults, and
26should not be modified - it will be updated with the latest recommended security 26should not be modified - it will be updated with the latest recommended security
27defaults between releases. To override the defaults, you should add more files to 27defaults between releases. To override the defaults, you should add more files to