From 65984d30e08ef77f8d173d22d1d332286aeb2ebe Mon Sep 17 00:00:00 2001 From: Raheman Vaiya Date: Tue, 19 Apr 2022 20:47:34 -0400 Subject: [PATCH] feature: Add command() --- data/keyd-application-mapper.1.gz | Bin 1484 -> 1489 bytes data/keyd.1.gz | Bin 5493 -> 5586 bytes docs/keyd-application-mapper.scdoc | 4 +-- docs/keyd.scdoc | 9 +++++ src/descriptor.c | 55 ++++++++++++++++++++++++----- src/descriptor.h | 1 + src/device.c | 4 +-- src/keyboard.c | 32 +++++++++++++++++ src/layer.h | 11 +++++- src/vkbd/uinput.c | 4 +-- 10 files changed, 105 insertions(+), 15 deletions(-) diff --git a/data/keyd-application-mapper.1.gz b/data/keyd-application-mapper.1.gz index 2ad79806b5be56567baa75d94565ea13c0a2c5d8..586f887f73e192ff170a82177b4bfd7d767092e6 100644 GIT binary patch delta 1479 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 diff --git a/data/keyd.1.gz b/data/keyd.1.gz index ef7b68d041f35e6e4ef2fd21884b2e49599cfb7e..0204a5601c3df34650ba3b674f5439a179d59193 100644 GIT binary patch literal 5586 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%0Dq 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 literal 5493 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 diff --git a/docs/keyd-application-mapper.scdoc b/docs/keyd-application-mapper.scdoc index d0fff91..48c4c82 100644 --- a/docs/keyd-application-mapper.scdoc +++ b/docs/keyd-application-mapper.scdoc @@ -76,8 +76,8 @@ to */var/run/keyd.socket* (i.e be a member of the *keyd* group). # A note on security -Any user which can interact with a program that directly controls input devices -should be assumed to have full access to the system. +*Any user which can interact with a program that directly controls input devices +should be assumed to have full access to the system.* While keyd offers slightly better isolation compared to other remappers by dint of mediating access through an IPC mechanism (rather than granting users diff --git a/docs/keyd.scdoc b/docs/keyd.scdoc index 59b6f6c..bc57fa3 100644 --- a/docs/keyd.scdoc +++ b/docs/keyd.scdoc @@ -372,6 +372,15 @@ arguments. macro2(400, 50, macro(Hello space World)) +*command()* + Execute the given shell command. + + E.G + + command(brightness down) + +*NOTE:* Commands are executed by root, which means any user which has access +to the keyd socket should be assumed to have root access. *noop* Do nothing. diff --git a/src/descriptor.c b/src/descriptor.c index d0e7244..933ad78 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -14,7 +14,9 @@ #define MAX_ARGS 5 -/* modifies the input string */ +/* TODO: Make this a bit nicer. */ + +/* Modifies the input string */ static int parse_fn(char *s, char **name, char *args[MAX_ARGS], @@ -314,13 +316,12 @@ static size_t escape(char *s) return n; } - static int parse_macro(const char *exp, struct macro *macro) { - char s[MAX_MACROEXP_LEN]; + char s[MAX_MACROEXP_LEN+1]; int len = strlen(exp); - if (len >= MAX_MACROEXP_LEN) { + if (len > MAX_MACROEXP_LEN) { err("macro exceeds maximum macro length (%d)", MAX_MACROEXP_LEN); return -1; } @@ -394,7 +395,7 @@ int layer_table_lookup(const struct layer_table *lt, const char *name) int layer_table_add_entry(struct layer_table *lt, const char *exp) { uint8_t code1, code2; - char *keystr, *descstr, *c, *s; + char *keystr, *descstr, *dot, *paren, *s; char *layername = "main"; struct descriptor d; struct layer *layer; @@ -410,10 +411,13 @@ int layer_table_add_entry(struct layer_table *lt, const char *exp) strcpy(buf, exp); s = buf; - if ((c = strchr(s, '.'))) { + dot = strchr(s, '.'); + paren = strchr(s, '('); + + if (dot && (!paren || dot < paren)) { layername = s; - *c = 0; - s = c+1; + *dot = 0; + s = dot+1; } if (parse_kvp(s, &keystr, &descstr) < 0) { @@ -518,6 +522,36 @@ int create_layer(struct layer *layer, const char *desc, const struct layer_table return 0; } +int set_command_arg(struct descriptor *d, int idx, + struct layer_table *lt, const char *exp) +{ + struct command *command = <->commands[lt->nr_commands]; + int len = strlen(exp); + + if (len == 0 || strstr(exp, "command(") != exp || exp[len-1] != ')') + return -1; + + if (lt->nr_commands >= MAX_COMMANDS) { + err("maximum number of commands exceeded"); + return 1; + } + + if (len > MAX_COMMAND_LEN) { + err("maximum command length exceeded"); + return 1; + } + + strcpy(command->cmd, exp+8); + command->cmd[len-9] = 0; + + command->cmd[len-1] = 0; + escape(command->cmd); + + d->args[0].idx = lt->nr_commands; + lt->nr_commands++; + return 0; +} + /* * Returns: * @@ -586,6 +620,11 @@ int parse_descriptor(const char *descstr, if (keycode_to_mod(code)) fprintf(stderr, "WARNING: mapping modifier keycodes directly may produce unintended results, you probably want layer() instead\n"); + } else if ((ret=set_command_arg(d, 0, lt, descstr)) >= 0) { + if (ret > 0) + return -1; + else + d->op = OP_COMMAND; } else if ((ret=set_macro_arg(d, 0, lt, descstr, -1, -1)) >= 0) { if (ret > 0) return -1; diff --git a/src/descriptor.h b/src/descriptor.h index d882cc4..e66994e 100644 --- a/src/descriptor.h +++ b/src/descriptor.h @@ -29,6 +29,7 @@ enum op { OP_TOGGLE, OP_MACRO, + OP_COMMAND, OP_TIMEOUT }; diff --git a/src/device.c b/src/device.c index d1a5151..f8e7bf5 100644 --- a/src/device.c +++ b/src/device.c @@ -68,7 +68,7 @@ static int device_init(const char *path, struct device *dev) int fd; int type; - if ((fd = open(path, O_RDWR | O_NONBLOCK, 0600)) < 0) { + if ((fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC, 0600)) < 0) { fprintf(stderr, "failed to open %s\n", path); return -1; } @@ -167,7 +167,7 @@ int devmon_create() assert(!init); init = 1; - int fd = inotify_init1(IN_NONBLOCK); + int fd = inotify_init1(IN_NONBLOCK | IN_CLOEXEC); if (fd < 0) { perror("inotify"); exit(-1); diff --git a/src/keyboard.c b/src/keyboard.c index f5baf79..608f090 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -324,6 +324,33 @@ static void activate_layer(struct keyboard *kbd, uint8_t code, struct layer *lay kbd->last_layer_code = code; } +static void execute_command(const char *cmd) +{ + int fd; + + dbg("Executing command: %s", cmd); + + if (fork()) + return; + + fd = open("/dev/null", O_RDWR); + + if (fd < 0) { + perror("open"); + exit(-1); + } + + close(0); + close(1); + close(2); + + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + + execl("/bin/sh", "/bin/sh", "-c", cmd); +} + static void clear_oneshot(struct keyboard *kbd) { size_t i = 0; @@ -348,6 +375,7 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, struct macro *macros = kbd->layer_table.macros; struct timeout *timeouts = kbd->layer_table.timeouts; struct layer *layers = kbd->layer_table.layers; + struct command *commands = kbd->layer_table.commands; switch (d->op) { struct macro *macro; @@ -476,6 +504,10 @@ static long process_descriptor(struct keyboard *kbd, uint8_t code, timeout = kbd->pending_timeout.t.timeout; } break; + case OP_COMMAND: + if (pressed) + execute_command(commands[d->args[0].idx].cmd); + break; case OP_SWAP: layer = &layers[d->args[0].idx]; macro = d->args[1].idx == -1 ? NULL : ¯os[d->args[1].idx]; diff --git a/src/layer.h b/src/layer.h index 53cd369..7172caa 100644 --- a/src/layer.h +++ b/src/layer.h @@ -16,6 +16,9 @@ #define MAX_MACRO_SIZE 64 #define MAX_MACROS 256 +#define MAX_COMMAND_LEN 256 +#define MAX_COMMANDS 64 + #define LT_NORMAL 0 #define LT_LAYOUT 1 #define LT_COMPOSITE 2 @@ -32,7 +35,7 @@ */ struct layer { - char name[MAX_LAYER_NAME_LEN]; + char name[MAX_LAYER_NAME_LEN+1]; size_t nr_layers; int layers[MAX_COMPOSITE_LAYERS]; @@ -48,6 +51,10 @@ struct layer { long activation_time; }; +struct command { + char cmd[MAX_COMMAND_LEN+1]; +}; + struct timeout { uint16_t timeout; struct descriptor d1; @@ -84,9 +91,11 @@ struct layer_table { struct timeout timeouts[MAX_TIMEOUTS]; struct macro macros[MAX_MACROS]; + struct command commands[MAX_COMMANDS]; size_t nr_macros; size_t nr_timeouts; + size_t nr_commands; }; #endif diff --git a/src/vkbd/uinput.c b/src/vkbd/uinput.c index b07109e..f6e91ff 100644 --- a/src/vkbd/uinput.c +++ b/src/vkbd/uinput.c @@ -36,7 +36,7 @@ static int create_virtual_keyboard(const char *name) size_t code; struct uinput_user_dev udev = {0}; - int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC); if (fd < 0) { perror("open uinput"); exit(-1); @@ -93,7 +93,7 @@ static int create_virtual_pointer(const char *name) uint16_t code; struct uinput_user_dev udev = {0}; - int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK); + int fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK | O_CLOEXEC); if (fd < 0) { perror("open"); exit(-1);