From 5813180a75aa1ef90f6d3459fc5beb099b815cfb Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 30 Apr 2020 18:32:44 +0200 Subject: [PATCH] tree-wide: port various bits over to locale_is_installed() (cherry picked from commit a00a78b84e2ab352b3144bfae8bc578d172303be) Resolves: #1755287 --- src/firstboot/firstboot.c | 30 ++++++++------ src/locale/localed.c | 87 ++++++++++++++++++++++++--------------- 2 files changed, 71 insertions(+), 46 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index a98e53b3a3..7e177a50fa 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -192,6 +192,14 @@ static int prompt_loop(const char *text, char **l, bool (*is_valid)(const char * } } +static bool locale_is_ok(const char *name) { + + if (arg_root) + return locale_is_valid(name); + + return locale_is_installed(name) > 0; +} + static int prompt_locale(void) { _cleanup_strv_free_ char **locales = NULL; int r; @@ -215,14 +223,14 @@ static int prompt_locale(void) { putchar('\n'); - r = prompt_loop("Please enter system locale name or number", locales, locale_is_valid, &arg_locale); + r = prompt_loop("Please enter system locale name or number", locales, locale_is_ok, &arg_locale); if (r < 0) return r; if (isempty(arg_locale)) return 0; - r = prompt_loop("Please enter system message locale name or number", locales, locale_is_valid, &arg_locale_messages); + r = prompt_loop("Please enter system message locale name or number", locales, locale_is_ok, &arg_locale_messages); if (r < 0) return r; @@ -780,11 +788,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_LOCALE: - if (!locale_is_valid(optarg)) { - log_error("Locale %s is not valid.", optarg); - return -EINVAL; - } - r = free_and_strdup(&arg_locale, optarg); if (r < 0) return log_oom(); @@ -792,11 +795,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_LOCALE_MESSAGES: - if (!locale_is_valid(optarg)) { - log_error("Locale %s is not valid.", optarg); - return -EINVAL; - } - r = free_and_strdup(&arg_locale_messages, optarg); if (r < 0) return log_oom(); @@ -922,6 +920,14 @@ static int parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } + /* We check if the specified locale strings are valid down here, so that we can take --root= into + * account when looking for the locale files. */ + + if (arg_locale && !locale_is_ok(arg_locale)) + return log_error_errno(EINVAL, "Locale %s is not installed.", arg_locale); + if (arg_locale_messages && !locale_is_ok(arg_locale_messages)) + return log_error_errno(EINVAL, "Locale %s is not installed.", arg_locale_messages); + return 1; } diff --git a/src/locale/localed.c b/src/locale/localed.c index 253973fd49..d6ed40babe 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -259,18 +259,57 @@ static void locale_free(char ***l) { (*l)[p] = mfree((*l)[p]); } +static int process_locale_list_item( + const char *assignment, + char *new_locale[static _VARIABLE_LC_MAX], + sd_bus_error *error) { + + assert(assignment); + assert(new_locale); + + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { + const char *name, *e; + + assert_se(name = locale_variable_to_string(p)); + + e = startswith(assignment, name); + if (!e) + continue; + + if (*e != '=') + continue; + + e++; + + if (!locale_is_valid(e)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s is not valid, refusing.", e); + if (locale_is_installed(e) <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s not installed, refusing.", e); + if (new_locale[p]) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name); + + new_locale[p] = strdup(e); + if (!new_locale[p]) + return -ENOMEM; + + return 0; + } + + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment); +} + static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; _cleanup_strv_free_ char **settings = NULL, **l = NULL; char *new_locale[_VARIABLE_LC_MAX] = {}, **i; _cleanup_(locale_free) _unused_ char **dummy = new_locale; bool modified = false; - int interactive, p, r; + int interactive, r; assert(m); assert(c); - r = bus_message_read_strv_extend(m, &l); + r = sd_bus_message_read_strv(m, &l); if (r < 0) return r; @@ -279,11 +318,13 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er return r; /* If single locale without variable name is provided, then we assume it is LANG=. */ - if (strv_length(l) == 1 && !strchr(*l, '=')) { - if (!locale_is_valid(*l)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data."); + if (strv_length(l) == 1 && !strchr(l[0], '=')) { + if (!locale_is_valid(l[0])) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid locale specification: %s", l[0]); + if (locale_is_installed(l[0]) <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified locale is not installed: %s", l[0]); - new_locale[VARIABLE_LANG] = strdup(*l); + new_locale[VARIABLE_LANG] = strdup(l[0]); if (!new_locale[VARIABLE_LANG]) return -ENOMEM; @@ -292,31 +333,9 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* Check whether a variable is valid */ STRV_FOREACH(i, l) { - bool valid = false; - - for (p = 0; p < _VARIABLE_LC_MAX; p++) { - size_t k; - const char *name; - - name = locale_variable_to_string(p); - assert(name); - - k = strlen(name); - if (startswith(*i, name) && - (*i)[k] == '=' && - locale_is_valid((*i) + k + 1)) { - valid = true; - - new_locale[p] = strdup((*i) + k + 1); - if (!new_locale[p]) - return -ENOMEM; - - break; - } - } - - if (!valid) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid Locale data."); + r = process_locale_list_item(*i, new_locale, error); + if (r < 0) + return r; } /* If LANG was specified, but not LANGUAGE, check if we should @@ -339,7 +358,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er } /* Merge with the current settings */ - for (p = 0; p < _VARIABLE_LC_MAX; p++) + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) if (!isempty(c->locale[p]) && isempty(new_locale[p])) { new_locale[p] = strdup(c->locale[p]); if (!new_locale[p]) @@ -348,7 +367,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er locale_simplify(new_locale); - for (p = 0; p < _VARIABLE_LC_MAX; p++) + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) if (!streq_ptr(c->locale[p], new_locale[p])) { modified = true; break; @@ -373,7 +392,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - for (p = 0; p < _VARIABLE_LC_MAX; p++) + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) free_and_replace(c->locale[p], new_locale[p]); r = locale_write_data(c, &settings);