[systemd-devel] [PATCH] localed: validate set-x11-keymap input
Lennart Poettering
lennart at poettering.net
Mon Nov 10 15:54:16 PST 2014
On Tue, 04.11.14 12:05, Jan Synacek (jsynacek at redhat.com) wrote:
> diff --git a/src/locale/localectl.c b/src/locale/localectl.c
> index d4a2d29..8f9e4da 100644
> --- a/src/locale/localectl.c
> +++ b/src/locale/localectl.c
> @@ -46,6 +46,7 @@
> #include "virt.h"
> #include "fileio.h"
> #include "locale-util.h"
> +#include "xkb-util.h"
>
> static bool arg_no_pager = false;
> static bool arg_ask_password = true;
> @@ -389,14 +390,7 @@ static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) {
> static int list_x11_keymaps(sd_bus *bus, char **args, unsigned n) {
> _cleanup_fclose_ FILE *f = NULL;
> _cleanup_strv_free_ char **list = NULL;
> - char line[LINE_MAX];
> - enum {
> - NONE,
> - MODELS,
> - LAYOUTS,
> - VARIANTS,
> - OPTIONS
> - } state = NONE, look_for;
> + enum keymap_state look_for;
While we don#t follow this rule too strictly we usually define typdefs
for enums and name them in CamelCase. Hence, please rename this type
"KeymapState" instead of "enum keymap_state".
That said, is "state" really the right name here? Shouldn't it be
"field" or "component" or "item" or so?
> !streq_ptr(variant, c->x11_variant) ||
> !streq_ptr(options, c->x11_options)) {
> + _cleanup_free_ char *msg = NULL;
>
> if ((layout && !string_is_safe(layout)) ||
> (model && !string_is_safe(model)) ||
> @@ -1050,6 +1052,12 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat
> free_and_strdup(&c->x11_options, options) < 0)
> return -ENOMEM;
>
> + r = xkb_validate_keymaps(model, layout, variant, options, &msg);
> + if (r < 0) {
> + log_error("Failed to validate X11 keyboard layout: %s", strerror(-r));
> + return sd_bus_error_set(error, SD_BUS_ERROR_FAILED, msg);
> + }
> +
Please return the error back to the client instead of logging it
away. Use sd_bus_error_setf() for that.
Use SD_BUS_ERROR_INVALID_ARGS as error id.
> +
> +static char **xkb_parse_argument(const char *arg)
> +{
> + _cleanup_free_ char *input;
> + char *token;
> + char **result = NULL;
> + int r;
> +
> + assert(arg);
> +
> + input = strdup(arg);
> + if (!input)
> + return NULL;
> +
> + token = strsep(&input, ",");
> + while(token) {
> + r = strv_extend(&result, token);
> + if (r < 0)
> + return NULL;
> + token = strsep(&input, ",");
> + }
> +
> + return result;
> +}
Please place the opening { of a function body on the same line as the
function declaration.
I figure strv_split() does exactly the same thing, please use that.
> +
> +int xkb_get_keymaps(char ***list, enum keymap_state look_for, const char *layout_prefix)
> +{
> + _cleanup_fclose_ FILE *f;
> + char line[LINE_MAX];
> + enum keymap_state state = NONE;
> + int r;
> +
> + f = fopen("/usr/share/X11/xkb/rules/base.lst", "re");
> + if (!f) {
> + log_error("Failed to open keyboard mapping list. %m");
> + return -errno;
> + }
This should probably become a function call that returns errors but
doesn't log about them, leaving that to the caller.
> +int xkb_validate_keymaps(const char *model,
> + const char *layouts_arg,
> + const char *variants_arg,
> + const char *options_arg,
> + char **error)
> +{
> + int r;
> +
> + if (layouts_arg) {
> + _cleanup_strv_free_ char **layouts_list = NULL;
> + char **it, **layouts;
> + int i = 0;
> +
> + r = xkb_get_keymaps(&layouts_list, LAYOUTS, NULL);
> + if (r < 0)
> + return r;
> +
> + layouts = strv_split(layouts_arg, ",");
> + if (!layouts)
> + return log_oom();
> +
> + STRV_FOREACH(it, layouts) {
> + _cleanup_strv_free_ char **variants_list = NULL;
> + bool variants_left = true;
> + int n;
> +
> + if (!strv_find(layouts_list, *it)) {
> + r = asprintf(error, "Requested layout '%s' not available.\n", *it);
> + if (r < 0)
> + return log_oom();
> + return -EINVAL;
> + }
> +
> + if (variants_left && variants_arg) {
> + _cleanup_strv_free_ char **variants;
> +
> + r = xkb_get_keymaps(&variants_list, VARIANTS, *it);
> + if (r < 0)
> + return r;
Hmm, reading the file over and over and over again sounds less than
ideal. Maybe we should intrdouce a struct here and then make
xkb_get_keymaps() return an array of structs really?
Lennart
--
Lennart Poettering, Red Hat
More information about the systemd-devel
mailing list