diff --git a/Makefile.am b/Makefile.am index 3f9f3fab37..1674f6195a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4626,7 +4626,12 @@ systemd_localed_SOURCES = \ systemd_localed_LDADD = \ libsystemd-label.la \ libsystemd-internal.la \ - libsystemd-shared.la + libsystemd-shared.la \ + $(XKBCOMMON_LIBS) + +systemd_localed_CFLAGS = \ + $(AM_CFLAGS) \ + $(XKBCOMMON_CFLAGS) nodist_systemunit_DATA += \ units/systemd-localed.service diff --git a/NEWS b/NEWS index f621752d64..0d3ab2b48b 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,12 @@ systemd System and Service Manager +CHANGES WITH 218: + + * If compiled with --enable-xkbcommon, systemd-localed will + verify x11 keymap settings by compiling the given keymap. It + will spew out warnings if the compilation fails. This + requires libxkbcommon to be installed. + CHANGES WITH 217: * journalctl gained the new options -t/--identifier= to match diff --git a/configure.ac b/configure.ac index 2c8be53dd3..bd3cc0ea61 100644 --- a/configure.ac +++ b/configure.ac @@ -414,6 +414,18 @@ if test "x$enable_kmod" != "xno"; then fi AM_CONDITIONAL(HAVE_KMOD, [test "$have_kmod" = "yes"]) +# ------------------------------------------------------------------------------ +have_xkbcommon=no +AC_ARG_ENABLE(xkbcommon, AS_HELP_STRING([--disable-xkbcommon], [disable xkbcommon keymap support])) +if test "x$enable_xkbcommon" != "xno"; then + PKG_CHECK_MODULES(XKBCOMMON, [ xkbcommon >= 0.3.0 ], + [AC_DEFINE(HAVE_XKBCOMMON, 1, [Define if libxkbcommon is available]) have_xkbcommon=yes], have_xkbcommon=no) + if test "x$have_xkbcommon" = xno -a "x$enable_xkbcommon" = xyes; then + AC_MSG_ERROR([*** xkbcommon support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_XKBCOMMON, [test "$have_xkbcommon" = "yes"]) + # ------------------------------------------------------------------------------ have_blkid=no AC_ARG_ENABLE(blkid, AS_HELP_STRING([--disable-blkid], [disable blkid support])) @@ -1374,6 +1386,7 @@ AC_MSG_RESULT([ polkit: ${have_polkit} efi: ${have_efi} kmod: ${have_kmod} + xkbcommon: ${have_xkbcommon} blkid: ${have_blkid} dbus: ${have_dbus} nss-myhostname: ${have_myhostname} diff --git a/src/locale/localed.c b/src/locale/localed.c index 9377ce5015..4e56382f4f 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -41,6 +41,10 @@ #include "event-util.h" #include "locale-util.h" +#ifdef HAVE_XKBCOMMON +#include +#endif + enum { /* We don't list LC_ALL here on purpose. People should be * using LANG instead. */ @@ -1005,6 +1009,51 @@ static int method_set_vc_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata return sd_bus_reply_method_return(m, NULL); } +#ifdef HAVE_XKBCOMMON +static void log_xkb(struct xkb_context *ctx, enum xkb_log_level lvl, const char *format, va_list args) { + /* suppress xkb messages for now */ +} + +static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { + const struct xkb_rule_names rmlvo = { + .model = model, + .layout = layout, + .variant = variant, + .options = options, + }; + struct xkb_context *ctx = NULL; + struct xkb_keymap *km = NULL; + int r; + + /* compile keymap from RMLVO information to check out its validity */ + + ctx = xkb_context_new(XKB_CONTEXT_NO_ENVIRONMENT_NAMES); + if (!ctx) { + r = -ENOMEM; + goto exit; + } + + xkb_context_set_log_fn(ctx, log_xkb); + + km = xkb_keymap_new_from_names(ctx, &rmlvo, XKB_KEYMAP_COMPILE_NO_FLAGS); + if (!km) { + r = -EINVAL; + goto exit; + } + + r = 0; + +exit: + xkb_keymap_unref(km); + xkb_context_unref(ctx); + return r; +} +#else +static int verify_xkb_rmlvo(const char *model, const char *layout, const char *variant, const char *options) { + return 0; +} +#endif + static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; const char *layout, *model, *variant, *options; @@ -1038,6 +1087,11 @@ static int method_set_x11_keyboard(sd_bus *bus, sd_bus_message *m, void *userdat (options && !string_is_safe(options))) return sd_bus_error_set_errnof(error, -EINVAL, "Received invalid keyboard data"); + r = verify_xkb_rmlvo(model, layout, variant, options); + if (r < 0) + log_warning("Cannot compile XKB keymap for new x11 keyboard layout ('%s' / '%s' / '%s' / '%s'): %s", + strempty(model), strempty(layout), strempty(variant), strempty(options), strerror(-r)); + r = bus_verify_polkit_async(m, CAP_SYS_ADMIN, "org.freedesktop.locale1.set-keyboard", interactive, &c->polkit_registry, error); if (r < 0) return r;