BUGS-NEWS
=========

Known issues and notable behaviour for localed 0.1.12.

BUGS
----

* The built-in keymap ↔ X11 conversion table is intentionally minimal.
  Keymaps not present in the table are silently ignored when convert=true
  is passed; the other side is left unchanged rather than guessing.
  A future release may read the full conversion table from the kbd(4)
  package data (typically /usr/share/kbd/keymaps/) if present.

* X11 keyboard config parsing uses a simple string-search strategy on the
  xorg.conf.d InputClass stanza.  Non-standard formatting (e.g. options on
  the same line, mixed quoting) may not be read back correctly.  Always use
  localectl or localed itself to write 00-keyboard.conf to avoid this.

* The Locale property array is populated in canonical variable order
  (LANG first, then LC_* alphabetically by the order in the spec).  Clients
  that compare the array as a bag of strings rather than a set should sort
  before comparing.

* locale.conf values containing a comma are accepted (LANGUAGE uses colons,
  but the safe-value check also allows commas for forward compatibility).
  Values containing characters outside [A-Za-z0-9_.@:,-] are rejected.

* The D-Bus bus policy (org.freedesktop.locale1.conf) contains an
  unrestricted <allow send_destination> rule in the default context, meaning
  any bus peer may send Set* method calls.  Authorisation is enforced by
  PolKit and the calls are harmless without a valid PolKit grant, but
  defence-in-depth would restrict Set* to privileged peers at the bus-policy
  layer as well.  This will be tightened in a future release.

FIXED IN 0.1.9
--------------

* localectl set-locale silently wrote to /etc/locale.conf instead of
  /etc/profile.d/lang.sh, so changes were never picked up by the daemon.
  (Fixed: rcl_write_lang_sh() now targets the correct file.)

* LANG_SH_FILE was undefined in localectl, causing "localectl status" to
  always show "n/a" for the system locale.
  (Fixed: variable defined at top of script.)

* localectl set-x11-keymap always failed with "command not found" because
  cmd_set_x11_keymap() was referenced in the dispatch table but never
  implemented.
  (Fixed: function fully implemented.)

* extract_xkb_option() imposed no length limit on parsed XKB values,
  making it possible for a malformed or adversarial xorg.conf.d file to
  produce arbitrarily long D-Bus property strings.
  (Fixed: MAX_XKB_VALUE_LEN = 256 enforced; oversized values ignored.)

* All four atomic write functions leaked the temp file on rename(2) failure.
  (Fixed: g_unlink(tmp_path) added to each rename-failure branch.)

* rcl_write_rc_keymap() wrote the keymap value unquoted into the generated
  rc.keymap shell script. The previous validator accepted shell metacharacters
  ($, `, !, etc.), allowing a crafted keymap name to inject arbitrary shell
  commands executed as root at boot.
  (Fixed: value double-quoted in the format string; validator tightened to
  allowlist [A-Za-z0-9\-_.,+:] in both the C daemon and localectl.)

* localectl rcl_write_x11_keyboard() wrote XKB field values inside a
  double-quoted heredoc, allowing $(...) expansion of layout/model/variant/
  options values.
  (Fixed: single-quoted heredoc for the static skeleton; printf '%s' for
  each variable field.)

* rcl_write_rc_keymap_toggle() had no return statement on the write path,
  making the gboolean result seen by the caller undefined behaviour.
  (Fixed: return ok added before closing brace.)

FIXED IN 0.1.10
---------------

* rcl_read_rc_keymap() returned the keymap name with surrounding double-quotes
  (e.g. `"us"` instead of `us`) after fix 8 (0.1.9) quoted the loadkeys
  argument in the generated rc.keymap script.  The VConsoleKeymap D-Bus
  property was therefore wrong after any write, breaking clients that compare
  the property value against known keymap names.
  (Fixed: quote-stripping added to the C reader and to the localectl awk
  extractor.)

* do_set_locale() in rcl-locale.c aliased locale[0] to a bare pointer before
  freeing and replacing it, creating a potential dangling-pointer hazard if
  the function were ever refactored.
  (Fixed: intermediate alias removed; locale[0] freed directly via an explicit
  expanded variable.)

* The terminal log handler in main.c called localtime() which is not
  thread-safe, as it returns a pointer to a static buffer.
  (Fixed: replaced with localtime_r() using a stack-allocated struct tm.)

* rcl_write_lang_sh() in localectl declared local variables (stripped, rest,
  lkey) inside a while-read loop body, shadowing outer-scope variables.
  (Fixed: local qualifiers removed; variables are now plain function-scoped
  assignments.)

FIXED IN 0.1.11
---------------

* keyboard_value_is_safe() in localectl still used the old blocklist (deny
  quotes, backslashes, control chars) after the C daemon was tightened to a
  strict allowlist in 0.1.9, leaving shell metacharacters accepted by the
  bash script.
  (Fixed: replaced with allowlist regex ^[A-Za-z0-9._,:+:-]+$ matching C.)

* do_set_locale() imposed no upper bound on the incoming locale array length,
  allowing an authorised client to force O(N*14) validation work per call.
  (Fixed: entry count checked before the loop; arrays over 14 entries
  rejected with G_DBUS_ERROR_INVALID_ARGS.)

* rcl_read_lang_sh() stored values read from lang.sh in the Locale D-Bus
  property without validating them against the safe charset, so a manually-
  edited file could expose unsafe strings on the bus.
  (Fixed: rcl_locale_value_is_safe() called on each value; failures skipped
  with a g_warning.)

* rcl_locale_daemon_finalize() did not clear priv->connection or zero
  priv->registration_id, leaking a GDBusConnection reference if the object
  was ever dropped without an explicit rcl_daemon_shutdown() call.
  (Fixed: same unregister-and-clear block added to finalize, guarded by the
  connection and registration_id checks.)

* do_set_locale() used manual g_free(key) on two early-return branches,
  fragile under future refactoring.
  (Fixed: g_autofree gchar *key used instead; all g_free(key) calls removed.)

* rcl_write_lang_sh() used g_hash_table_new() with no destructors and no
  comment explaining the borrowed-pointer ownership model.
  (Fixed: switched to g_hash_table_new_full(..., NULL, NULL) with an
  explicit ownership contract comment.)

* list-keymaps and list-locales passed user-supplied filter arguments
  directly to grep -i, allowing ERE metacharacters and option injection.
  (Fixed: changed to grep -iF in both commands.)

* rcl_write_lang_sh() in localectl re-emitted preserved cur_val entries
  without validating them, propagating unsafe values from a manually-edited
  lang.sh on the next write.
  (Fixed: locale_value_is_safe() called on cur_val; unsafe values dropped.)

* read_x11_keyboard_conf() did not validate the character set of XKB values
  extracted from 00-keyboard.conf, so unsafe values could be served as D-Bus
  properties.
  (Fixed: SANITISE_XKB macro applies rcl_keyboard_value_is_safe() to all
  four fields; unsafe values reset to empty string with g_warning.)

FIXED IN 0.1.12
---------------

* rcl_read_rc_keymap_toggle() returned the sidecar file content verbatim
  with no allowlist check, unlike VConsoleKeymap, X11Layout, X11Model,
  X11Variant, and X11Options which all validate on read.  A local user able
  to write /etc/rc.d/rc.keymap.toggle could inject arbitrary content into
  the VConsoleKeymapToggle D-Bus property.
  (Fixed: rcl_keyboard_value_is_safe() applied after whitespace-stripping;
  values outside [A-Za-z0-9\-_.,+:] are silently reset to empty string.)

* rcl_write_lang_sh() and rcl_write_rc_keymap_toggle() wrote their temp files
  with mode 0600 (the g_file_set_contents() default) and did not chmod before
  the rename.  A from-scratch write of lang.sh produced a file unreadable by
  login shells, silently breaking locale for all non-root users.
  (Fixed: g_chmod(tmp_path, 0644) added before g_rename() in both writers.)

* kv_read() and kv_set() were defined in localectl but never called.  kv_set()
  passed the caller-supplied key directly to grep as a pattern, making it
  vulnerable to regex injection if invoked with unvalidated input.
  (Fixed: both functions removed; rcl_lang_sh_get() and rcl_write_lang_sh()
  cover the same roles with proper validation.)

REPORTING BUGS
--------------

Please report bugs at https://github.com/nater1983/localed/issues
