Skip to content

Releases: MAButz/ldm

ldm 3.4.12-1

Choose a tag to compare

@MAButz MAButz released this 09 Oct 12:21

Start the RDP session without sound rather than not at all.

FreeRDP ends the whole connection when /sound or /microphone finds no PulseAudio-compatible server. ldm now looks for one before starting xfreerdp (PULSE_SERVER, $XDG_RUNTIME_DIR/pulse/native, /run/user/<uid>/pulse/native, /run/pulse/native) and passes it on in PULSE_SERVER. If none answers, it leaves the sound options out and logs why.

ldm 3.4.11-1

Choose a tag to compare

@MAButz MAButz released this 07 Oct 20:10

The greeter is sized for the monitor it is on.

The greeter took its size from monitor 0 and put every window at the top-left corner of the screen - the same monitor only by luck. LTSP sets several outputs side by side, each --left-of the one before, so the monitor at that corner is the last output, not the first. With outputs of different sizes the prompt sat on a large monitor sized for a small one: the picture filled a corner, the rest was black, and the fields and the pointer were off-centre.

Measured with two outputs on a virtual X server - 2560×1440 at the corner, 1920×1080 as monitor 0:

before now
large monitor (prompt) picture in a 1920×1080 corner, rest black filled, fields centred
small monitor black the picture, fitted to its own size
pointer 960,540 1280,720

The prompt stays where it has always been, on the monitor at the top-left corner, and takes that monitor's size, background included. The host, language and preference windows follow, because GTK centres them under the pointer and the pointer now starts in the middle of that monitor.

Mirrored outputs are left as they were: fitting the picture to the larger one as well put a second horizon around the first. A single monitor and mirrored outputs are pixel-identical to 3.4.10-1 - the only difference found was the clock's minute.

ldm 3.4.10-1

Choose a tag to compare

@MAButz MAButz released this 07 Oct 07:43

Options a client picks by the FreeRDP it actually has, for a fleet halfway through a migration.

Some clients still run FreeRDP 2, others already run 3, and one RDP_OPTIONS line cannot serve them: the two do not take the same spellings. FreeRDP 3 rejects what it does not know by printing its entire help and exiting before it connects — which on a client looks like the session ending the instant the greeter disappears, with nothing said anywhere the user can see.

Measured against 3.15.0, these are refused:

Written for FreeRDP 2 FreeRDP 3
/cert-ignore /cert:ignore
/kbd:0x00000407, /kbd:German, /kbd:de /kbd:layout:0x407
-sec-nla /sec:nla:off or /sec:rdp
/gfx-h264:avc420 /gfx:avc420
/tls-seclevel:0 /tls:seclevel:0
+async-input, +glyph-cache gone, drop them

/cert-ignore is in practically every configuration written for FreeRDP 2, so rewriting RDP_OPTIONS for the new clients breaks every old one — and the usual answer, a per-client section naming every machine, means knowing in advance which is which, which is exactly what nobody has during a migration.

RDP3_OPTIONS and RDP2_OPTIONS are read only by a client about to run that major version, with RDP3_OPTIONS_<screen> beside the RDP_OPTIONS_<screen> that already existed:

RDP3_OPTIONS_07     that version, that screen
RDP3_OPTIONS        that version
RDP_OPTIONS_07      that screen, whatever the version
RDP_OPTIONS         everybody

The first that exists wins outright rather than adding to the one below it — a line still carrying /cert-ignore would defeat the point. The client decides for itself: the binary's name settles the version in the normal case, and where it does not (an admin pointing RDP_XFREERDP_BIN at something of their own) the binary is asked once with --version. So no machine has to be listed anywhere, and the RDP_OPTIONS line the old fleet depends on is never touched.

A half-migrated site therefore needs two lines and no inventory:

RDP_OPTIONS="/cert-ignore /sound +clipboard /f"      # unchanged
RDP3_OPTIONS="/cert:ignore /sound +clipboard /f"     # only clients with FreeRDP 3

Also: the variable that won is written to the log with its value. The first question when a session dies immediately is which options it started with, and until now the log said only "Verwende Standard RDP_OPTIONS".

See lts.conf(5) in ltsp 6.3.26-1, which carries the full list — including the long list of options that did survive, because the useful answer to "will my line break" is mostly no, with those few exceptions.

ldm 3.4.9-1

Choose a tag to compare

@MAButz MAButz released this 30 Sep 14:46

The password change speaks German again on a German client.

Its strings went through gettext() from the start and still came out English: when the Kerberos code moved into src/ldmkrb5.c in 3.4.8-1, that file was never added to po/POTFILES.in. xgettext never saw it, so no catalogue could hold what it says — and the greeter around it was German, asking for a "New password" beside Benutzername and Passwort.

The half that is easy to miss: msgmerge had already matched some of those strings to unrelated older entries and marked them fuzzy, and gettext refuses a fuzzy translation. They were English too, while looking translated in the file. One of them would have been worse than English if it had ever been shown:

"The new password does not meet the rules of this domain." → "Diesen Benutzer gibt es in der Domäne nicht."

Sixty-one messages now, none fuzzy, none open, checked against the compiled catalogue rather than the source: the prompts, the line saying the password must be changed before signing in, the mismatch notice, every reason a change can fail, and the message for an authentication server that cannot be reached. Three older strings that had never been translated came along — the reboot notice from I01-nbd-checkupdate, the question about a session elsewhere, and S15-userLoginCheck's refusal.

What deliberately stays in the domain's own language is the controller's wording when it refuses a password. "Password too short, password must be at least 7 characters long" is its sentence about its own rule, and passing it through unchanged is the whole point of showing it.

For any of this to be seen, the environment has to be German: LANG="de_DE.UTF-8" in lts.conf, and the locale has to be in the image (ltsp-build-client --locale de_DE.UTF-8,...). Where it is not, everything stays English without an error, and ldm says so in its log: locale "de_DE.UTF-8" is not generated in this image; staying in "C" and showing English.

ldm 3.4.8-1

Choose a tag to compare

@MAButz MAButz released this 29 Sep 14:14

A domain password that must be changed can now be changed at the login screen.

ldm could say a password had expired and nothing else. On a thin client that is the worse half of the message: the client is not a domain member, there is no local tool to change a domain password with, and the session server only repeats the refusal. The user was told to do something the machine gave them no way to do.

Two situations arrive here and the protocol does not tell them apart. One is a password that ran out. The other is an account that never had one of the user's own — an administrator set an initial password and marked it to be replaced at first sign-in, which is pwdLastSet=0 in Active Directory and the REQUIRES_PWCHANGE attribute on an MIT KDC. Measured on the latter: such an account reports Password expiration date: [never] and the KDC still answers KDC_ERR_KEY_EXPIRED. That is why the wording says a password must be changed rather than that it expired — for somebody who has just been handed one, "expired" is not true.

How it works. A KDC still issues a ticket for kadmin/changepw when the password has to be changed. That ticket is good for nothing else, and it is exactly what a login screen needs. ldm asks for the new password twice, sets it with that ticket over the protocol from RFC 3244 — which is what Active Directory speaks — and then signs in with the new password, so the session starts without a second login. The domain clears the expiry or the attribute as part of the change; the next sign-in asks nothing.

The greeter needed no new commands: its protocol already sets a prompt and takes an answer with the entry hidden, so the two extra questions work with every existing theme.

What is deliberately not done here. No rule is enforced on this side. Length, complexity, history and minimum age belong to the domain controller, and when it refuses, its own wording is what the user is shown — it describes the rule that actually applies, which nothing invented here could. Changing needs the controller holding the PDC emulator role, so a site with a second controller can sign in while the first is down but not change passwords; the message says that rather than blaming the password. Failures are told apart for the same reason: a controller that cannot be reached, a password service that does not answer, and a change the domain refused each say their own thing, or whoever reads the message goes looking at the wrong machine.

The new password goes to the KDC and nowhere else. It reaches the session server afterwards as the account's actual password, and both it and the old one are wiped rather than freed.

A KDC that does not answer still stops the login, and that is a decision. The credentials were never checked by anyone, and a session started with them lands in the xrdp dialog this whole check exists to avoid. The message says the authentication server cannot be reached and that the password is not the problem; the krb5 detail goes to the log.

Settings: RDP_PREAUTH_CHANGE_PASSWORD=False turns the offer off. LDM_NEWPASSWORD_PROMPT, LDM_NEWPASSWORD_AGAIN_PROMPT and LDM_NEWPASSWORD_MESSAGE carry a site's own wording. See ldm(1), section PASSWORDS THAT MUST BE CHANGED, and lts.conf(5).

Also in this release: the Kerberos code moved out of the xfreerdp plugin into src/ldmkrb5.c. The plugin had grown to 1383 lines doing three jobs, and the name of the file described the least of them. ldm links -lkrb5 now; the plugin no longer does and resolves ldm_krb5_* from the program that loads it, the way it already resolves ldm_lockout_*.

Tested against a local MIT KDC across ten scenarios: correct and wrong passwords, an expired password changed and used, mismatched entries, a cancelled change, the offer switched off, a policy rejection showing the server's own words, an unreachable KDC, a realm that is not configured, and a password service that does not answer. Not yet exercised against a real Active Directory.

ldm 3.4.7-1

Choose a tag to compare

@MAButz MAButz released this 22 Sep 07:56

An empty answer is no longer taken for a credential.

The greeter remaps Tab to Enter, so two taps sent an empty username and an empty password straight through, and nothing rejected them. With no credentials to ask about, the pre-authentication reports itself unavailable rather than refused — and unavailable is not a refusal, so the session started anyway and handed the user the RDP server's own login window. Past the greeter, past the pre-authentication, and past the failure count that goes with it.

This is not a way in without a password: the RDP server still asks. What it bypassed is the check in front of it and the counting that goes with it, which is the part meant to stop someone at a client guessing indefinitely without it showing up anywhere.

  • get_userid() and get_passwd() ask again while the answer is empty. That is the one place every backend and every way of submitting passes through, so it does not matter whether the empty line came from Tab, from Enter, or from something else driving the greeter.
  • Both backends now treat an empty string as missing rather than only a null pointer, so nothing starts a session on one.
  • The guest path in the ssh backend is untouched: it fills in a user name and password of its own, and they are never empty.

Reported by Marc-André Butz while testing the RDP backend with RDP_PREAUTH=ssh.

ldm 3.4.6-1

Choose a tag to compare

@MAButz MAButz released this 22 Sep 07:34

The greeter says which lock keys are on, below the entry, the way a Windows login screen does.

Getting the password wrong because Caps Lock was left on is a common way to be locked out, and the greeter gave no hint of it. On a thin client it is worse than on a desktop: the lamp on the keyboard in front of the user is driven by the client's own X server and need not agree with the session at all.

  • Reads GDK's keymap and follows its state-changed signal, so every change is reported — including the ones that do not come from typing — and there is nothing to poll.
  • Empty when neither lock key is on, and the label keeps its line height then, so the dialogue does not jump as the text comes and goes.
  • Translated: Feststelltaste ist aktiviert, Num-Lock ist aktiviert.
  • Named #ldm-lockkeys so a theme can style it along with the other labels that sit on the background image. A theme with a dark background will want to add it to its rule — in the default near-black it would be unreadable.

ldm 3.4.5-1

Choose a tag to compare

@MAButz MAButz released this 20 Sep 11:51

The German translation covers the whole interface again.

po/de.po held 20 of 44 strings, and the 24 it was missing were not the incidental ones:

  • every button in the dialogs — Cancel, Apply, OK — so a German greeter offered Abbrechen nowhere and Cancel everywhere;
  • every message a failed sign-in produces: wrong password, unknown user, locked account, expired password, unreachable authentication server, clock skew, session taken over by another connection, account not allowed to log on remotely. Precisely the words a user has to read and act on, in English on an otherwise German screen;
  • the lockout warnings, including the one naming how long the computer stays blocked.

The two that count durations, %d second and %d minute, go through ngettext, and the file had no Plural-Forms header at all — so those two could never have worked. It has one now. 44 translated, none left untranslated.

The Preferences button carries a name too: #ldm-preferences.

It is drawn with relief NONE — no ground of its own, sitting straight on the theme's background image exactly as the four named labels do. A theme that lightens the labels for a dark photograph and has no way to reach this one leaves a single word in the default near-black.

#ldm-prompt, #ldm-status, #ldm-host, #ldm-clock, #ldm-preferences {
    color: #f2f2f2;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.85);
}

ldm 3.4.4-1

Choose a tag to compare

@MAButz MAButz released this 20 Sep 06:45

The greeter says so when the language it was asked for cannot be had.

setlocale(LC_ALL, "") returns NULL when LANG names a locale the image does not carry, and leaves the process in C - where glibc also ignores LANGUAGE, deliberately, with C.UTF-8 counting as C for that purpose. Every string then stays in English and nothing anywhere says why. Somebody who has just written LANG into lts.conf and rebooted a client deserves better than an unchanged screen:

locale "de_DE.UTF-8" is not generated in this image; staying in "C"
and showing English. Build the image with ltsp-build-client --locale
to include it.

and for the other case:

LANGUAGE is set but the locale is "C", and glibc ignores LANGUAGE in
the C locale. The image needs one real locale - any one - for LANGUAGE
to take effect.

Both at log level 3, so they appear without LDM_LOGLEVEL being raised. See ltsp 6.3.14-1, whose --locale puts the locales into the image in the first place.

ldm 3.4.3-1

Choose a tag to compare

@MAButz MAButz released this 19 Sep 17:54

The greeter draws the icons on its buttons and menu entries again.

It had never stopped asking for them - gtk_button_set_image() on the preferences button, gtk_image_menu_item_set_image() on every menu entry - and under GTK2 they appeared. GTK 3.10 flipped gtk-button-images and gtk-menu-images to FALSE, and from then on both calls were ignored without a word: the icons were still read out of the theme directory, still attached to the widgets, and never drawn. What was left is a login screen carrying text and nothing else, beside a theme directory full of icons that look perfectly fine in an image viewer.

Both settings are now turned on at startup. A desktop is right to ignore an application that overrides the user preference here; a greeter has no user yet and no settings daemon behind it, and what it shows is what its theme says it shows.

The preferences icon is a cog wheel. It was a hammer crossed with a wrench, which reads as repair work rather than settings - and nobody had seen it since GTK 3.10 anyway. Drawn for this package at 24x24 to match the rest of the set, so no question arises about the licence of a borrowed icon set.

The icons a theme may carry are listed in lts.conf(5) as of ltsp 6.3.13-1: preferences, host, session, language, reboot, shutdown, backend.