diff --git a/include/sway/commands.h b/include/sway/commands.h index ccc3cf584..9e8d013ec 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -54,7 +54,7 @@ int sp_index; /** * Parse and handles a command. */ -struct cmd_results *handle_command(char *command); +struct cmd_results *handle_command(char *command, enum command_context context); /** * Parse and handles a command during config file loading. * diff --git a/include/sway/security.h b/include/sway/security.h index aa51fd815..1cc85beec 100644 --- a/include/sway/security.h +++ b/include/sway/security.h @@ -6,6 +6,8 @@ enum secure_feature get_feature_policy(pid_t pid); enum command_context get_command_policy(const char *cmd); +const char *command_policy_str(enum command_context context); + struct feature_policy *alloc_feature_policy(const char *program); struct command_policy *alloc_command_policy(const char *command); diff --git a/sway/commands.c b/sway/commands.c index 0bfe9d13f..5d5087b13 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -323,7 +323,7 @@ static struct cmd_handler *find_handler(char *line, enum cmd_status block) { return res; } -struct cmd_results *handle_command(char *_exec) { +struct cmd_results *handle_command(char *_exec, enum command_context context) { // Even though this function will process multiple commands we will only // return the last error, if any (for now). (Since we have access to an // error string we could e.g. concatonate all errors there.) @@ -397,6 +397,16 @@ struct cmd_results *handle_command(char *_exec) { free_argv(argc, argv); goto cleanup; } + if (!(get_command_policy(argv[0]) & context)) { + if (results) { + free_cmd_results(results); + } + results = cmd_results_new(CMD_INVALID, cmd, + "Permission denied for %s via %s", cmd, + command_policy_str(context)); + free_argv(argc, argv); + goto cleanup; + } struct cmd_results *res = handler->handle(argc-1, argv+1); if (res->status != CMD_SUCCESS) { free_argv(argc, argv); diff --git a/sway/handlers.c b/sway/handlers.c index a329329df..ee52ba38f 100644 --- a/sway/handlers.c +++ b/sway/handlers.c @@ -386,7 +386,7 @@ static bool handle_view_created(wlc_handle handle) { struct criteria *crit = criteria->items[i]; sway_log(L_DEBUG, "for_window '%s' matches new view %p, cmd: '%s'", crit->crit_raw, newview, crit->cmdlist); - struct cmd_results *res = handle_command(crit->cmdlist); + struct cmd_results *res = handle_command(crit->cmdlist, CONTEXT_CRITERIA); if (res->status != CMD_SUCCESS) { sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); } @@ -585,7 +585,7 @@ static void handle_binding_command(struct sway_binding *binding) { reload = true; } - struct cmd_results *res = handle_command(binding->command); + struct cmd_results *res = handle_command(binding->command, CONTEXT_BINDING); if (res->status != CMD_SUCCESS) { sway_log(L_ERROR, "Command '%s' failed: %s", res->input, res->error); } @@ -936,18 +936,18 @@ bool handle_pointer_scroll(wlc_handle view, uint32_t time, const struct wlc_modi int y_amount = (int)_amount[1]; if (x_amount > 0 && strcmp(config->floating_scroll_up_cmd, "")) { - handle_command(config->floating_scroll_up_cmd); + handle_command(config->floating_scroll_up_cmd, CONTEXT_BINDING); return EVENT_HANDLED; } else if (x_amount < 0 && strcmp(config->floating_scroll_down_cmd, "")) { - handle_command(config->floating_scroll_down_cmd); + handle_command(config->floating_scroll_down_cmd, CONTEXT_BINDING); return EVENT_HANDLED; } if (y_amount > 0 && strcmp(config->floating_scroll_right_cmd, "")) { - handle_command(config->floating_scroll_right_cmd); + handle_command(config->floating_scroll_right_cmd, CONTEXT_BINDING); return EVENT_HANDLED; } else if (y_amount < 0 && strcmp(config->floating_scroll_left_cmd, "")) { - handle_command(config->floating_scroll_left_cmd); + handle_command(config->floating_scroll_left_cmd, CONTEXT_BINDING); return EVENT_HANDLED; } } @@ -960,7 +960,7 @@ static void handle_wlc_ready(void) { config->active = true; while (config->cmd_queue->length) { char *line = config->cmd_queue->items[0]; - struct cmd_results *res = handle_command(line); + struct cmd_results *res = handle_command(line, CONTEXT_CONFIG); if (res->status != CMD_SUCCESS) { sway_log(L_ERROR, "Error on line '%s': %s", line, res->error); } diff --git a/sway/ipc-server.c b/sway/ipc-server.c index ebb5ce583..e575081b2 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c @@ -312,7 +312,7 @@ void ipc_client_handle_command(struct ipc_client *client) { switch (client->current_command) { case IPC_COMMAND: { - struct cmd_results *results = handle_command(buf); + struct cmd_results *results = handle_command(buf, CONTEXT_IPC); const char *json = cmd_results_to_json(results); char reply[256]; int length = snprintf(reply, sizeof(reply), "%s", json); diff --git a/sway/security.c b/sway/security.c index 670cae56e..2ccc30fda 100644 --- a/sway/security.c +++ b/sway/security.c @@ -64,3 +64,20 @@ enum command_context get_command_policy(const char *cmd) { return default_policy; } + +const char *command_policy_str(enum command_context context) { + switch (context) { + case CONTEXT_ALL: + return "all"; + case CONTEXT_CONFIG: + return "config"; + case CONTEXT_BINDING: + return "binding"; + case CONTEXT_IPC: + return "IPC"; + case CONTEXT_CRITERIA: + return "criteria"; + default: + return "unknown"; + } +}