From a00a78b84e2ab352b3144bfae8bc578d172303be 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() --- src/firstboot/firstboot.c | 28 ++++++++----- src/home/homectl.c | 3 ++ src/locale/localed.c | 87 ++++++++++++++++++++++++--------------- src/login/pam_systemd.c | 4 +- 4 files changed, 76 insertions(+), 46 deletions(-) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 488e87beae6..f9fdf7b1d7f 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -205,6 +205,14 @@ static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*i } } +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; @@ -238,7 +246,7 @@ static int prompt_locale(void) { print_welcome(); r = prompt_loop("Please enter system locale name or number", - locales, 60, locale_is_valid, &arg_locale); + locales, 60, locale_is_ok, &arg_locale); if (r < 0) return r; @@ -246,7 +254,7 @@ static int prompt_locale(void) { return 0; r = prompt_loop("Please enter system message locale name or number", - locales, 60, locale_is_valid, &arg_locale_messages); + locales, 60, locale_is_ok, &arg_locale_messages); if (r < 0) return r; @@ -791,10 +799,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_LOCALE: - if (!locale_is_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Locale %s is not valid.", optarg); - r = free_and_strdup(&arg_locale, optarg); if (r < 0) return log_oom(); @@ -802,10 +806,6 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_LOCALE_MESSAGES: - if (!locale_is_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Locale %s is not valid.", optarg); - r = free_and_strdup(&arg_locale_messages, optarg); if (r < 0) return log_oom(); @@ -927,6 +927,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(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale); + if (arg_locale_messages && !locale_is_ok(arg_locale_messages)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages); + return 1; } diff --git a/src/home/homectl.c b/src/home/homectl.c index c98bf8b5408..e1857b69234 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -2807,6 +2807,9 @@ static int parse_argv(int argc, char *argv[]) { if (!locale_is_valid(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale '%s' is not valid.", optarg); + if (locale_is_installed(optarg) <= 0) + log_warning("Locale '%s' is not installed, accepting anyway.", optarg); + r = json_variant_set_field_string(&arg_identity_extra, "preferredLanguage", optarg); if (r < 0) return log_error_errno(r, "Failed to set preferredLanguage field: %m"); diff --git a/src/locale/localed.c b/src/locale/localed.c index acdf79fa6b3..a6aa3bae8c8 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -258,18 +258,57 @@ static int property_get_xkb( return -EINVAL; } +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) { _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {}; _cleanup_strv_free_ char **settings = NULL, **l = NULL; Context *c = userdata; bool modified = false; - int interactive, p, r; + int interactive, r; char **i; 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; @@ -278,11 +317,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; @@ -291,31 +332,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 @@ -338,7 +357,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]) @@ -347,7 +366,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; @@ -372,7 +391,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); diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 84bea21ab7b..b07773088e2 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -580,9 +580,9 @@ static int apply_user_record_settings(pam_handle_t *handle, UserRecord *ur, bool if (pam_getenv(handle, "LANG")) { if (debug) pam_syslog(handle, LOG_DEBUG, "PAM environment variable $LANG already set, not changing based on user record."); - } else if (!locale_is_valid(ur->preferred_language)) { + } else if (locale_is_installed(ur->preferred_language) <= 0) { if (debug) - pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid locally, not setting $LANG."); + pam_syslog(handle, LOG_DEBUG, "Preferred language specified in user record is not valid or not installed, not setting $LANG."); } else { _cleanup_free_ char *joined = NULL; -- 2.47.3