fix: a hidden Wi-Fi survives the hand-over, and a failed one leaves an owner
The prayer-room laptop's 0.2.5 migration built a NetworkManager connection, could not bring it up, rolled back, and left the wireless adapter belonging to nobody. Four separate defects, each of which would have been enough on its own. THE HIDDEN FLAG WAS THROWN AWAY. The stanza said wpa-scan-ssid 1 and the parser read it — into options, where the only accessor ignored it. The profile came out with 802-11-wireless.hidden: no, and NetworkManager will not associate with an SSID it has not seen in a scan. A hidden one is never in a scan. credentials() returned a pair; profile() now returns the whole network, and add() writes the flag in BOTH directions rather than only when true, because a default that happens to be right is not the same as an answer. IFDOWN RAN AFTER THE STANZA WAS COMMENTED OUT. ifupdown reads /etc/network/interfaces to find out how to bring an interface down; with the stanza gone it says "Ignoring unknown interface" and does nothing. So ifupdown's own wpa_supplicant and DHCP client were still holding the radio when NetworkManager was asked to associate with it, which is a fight NetworkManager loses. Down first, while the file still says how; rewrite the file second. THE ROLLBACK LEFT THE ADAPTER UNMANAGED. restore() ended with `device set <dev> managed no`, which is right while ifupdown can bring the interface up and is a radio nobody owns when ifup has failed too. That is the state the laptop was found in, and why `nmcli device set wlp2s0 managed yes` was a manual recovery step. It now escalates: if ifupdown cannot get the network back either, the interface goes to NetworkManager rather than to neither, and it says so loudly. A '#' IN A PASSWORD WAS SILENTLY TRUNCATED. The parser cut every line at its first '#'. interfaces(5) is explicit that only whole-line comments exist, so a pre-shared key containing one became a prefix of itself — and the only symptom is an association failing exactly the way a wrong password fails. Two smaller ones went with them. The rollback un-comments its own marked lines in place rather than copying the backup over the whole file, so a wired change made between the migration and the rollback is no longer silently reverted. And nmcli terse output is split on its own escaping rules under LC_ALL=C, so a network whose name contains a colon cannot make a successful migration look like a failed one. --adopt now also refuses a network it cannot recreate before taking the interface away from ifupdown to find out, and reports an unmanaged-devices line in NetworkManager's configuration, which survives the stanza going away. Verified against a real NetworkManager 1.52.1: the keyfile carries hidden=true, the SSID keeps its space, and a psk containing '#' is intact, at 0600 root:root with no connection.permissions. The new test drives the whole hand-over against stubbed tools and asserts the ordering, the rollback and the managed state — including that a machine already migrated, which is the laptop, is not migrated again. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 5
parent
fe08363534
commit
30d2d99230
@@ -154,6 +154,74 @@ that would be a one-way door.
|
||||
|
||||
The original is kept at `/etc/network/interfaces.before-ekklesia-classroom`.
|
||||
|
||||
### What 0.2.5 got wrong, and what 0.2.6 changed
|
||||
|
||||
The prayer-room laptop's Wi-Fi is **hidden** — `ROGC Classroom`, an SSID
|
||||
with a space in it, announced by nothing. `--adopt` built a connection,
|
||||
failed to bring it up, rolled back, and left the adapter belonging to
|
||||
nobody. Four separate defects, all fixed:
|
||||
|
||||
**1. The hidden flag was thrown away.** The stanza said `wpa-scan-ssid 1`
|
||||
and the parser read it — into `options`, where the only accessor ignored
|
||||
it. The generated profile had `802-11-wireless.hidden: no`, and
|
||||
NetworkManager will not associate with an SSID it has not seen in a scan.
|
||||
A hidden one is never in a scan. `credentials()` returned a pair; there
|
||||
is now a `profile()` that returns the whole network, and `add()` writes
|
||||
`802-11-wireless.hidden` in **both** directions rather than only when
|
||||
true — a default that happens to be right is not an answer.
|
||||
|
||||
**2. `ifdown` ran after the stanza was commented out.** ifupdown reads
|
||||
`/etc/network/interfaces` to find out how to bring an interface down.
|
||||
With the stanza gone it says *"Ignoring unknown interface"* and does
|
||||
nothing — so ifupdown's own `wpa_supplicant` and DHCP client were still
|
||||
holding the radio when NetworkManager was asked to associate with it.
|
||||
Two supplicants on one interface is a fight NetworkManager loses. The
|
||||
order is now: **`ifdown` first, while the file still says how; rewrite
|
||||
the file second.**
|
||||
|
||||
**3. The rollback left the adapter unmanaged.** `restore()` ended with
|
||||
`nmcli device set <dev> managed no`, which is right while ifupdown can
|
||||
actually bring the interface up. When `ifup` fails too, those two lines
|
||||
are a wireless adapter neither manager owns: no connection, and a panel
|
||||
that cannot even scan. That is the state the laptop was found in, and it
|
||||
is why `sudo nmcli device set wlp2s0 managed yes` was a manual recovery
|
||||
step. The rollback now escalates — if ifupdown cannot get the network
|
||||
back either, the interface is handed to NetworkManager rather than left
|
||||
with neither, and it says so loudly.
|
||||
|
||||
**4. A `#` in a password was silently truncated.** The parser cut every
|
||||
line at its first `#`. `interfaces(5)` is explicit that only whole-line
|
||||
comments exist — *"end-of-line comments are NOT supported"* — so a
|
||||
pre-shared key containing `#` became a prefix of itself, and the only
|
||||
symptom is an association that fails exactly the way a wrong password
|
||||
fails.
|
||||
|
||||
Two smaller ones went with them. The rollback un-comments its own marked
|
||||
lines in place instead of copying the backup over the whole file, because
|
||||
the backup is written once and never refreshed — a whole-file restore
|
||||
silently reverted any *wired* change an administrator made in between.
|
||||
And `nmcli -t` output is now split on its own escaping rules rather than
|
||||
on `:`, with `LC_ALL=C`, so a network whose name contains a colon cannot
|
||||
make a successful migration look like a failed one.
|
||||
|
||||
`--adopt` also now refuses a network it cannot recreate — WPA-Enterprise
|
||||
has no pre-shared key to carry across — *before* taking the interface
|
||||
away from ifupdown to find out, and reports any `unmanaged-devices` line
|
||||
in NetworkManager's own configuration, which survives the stanza going
|
||||
away and would otherwise leave the interface belonging to nobody after a
|
||||
restart.
|
||||
|
||||
Verified against a real NetworkManager 1.52.1: the keyfile it writes
|
||||
carries `hidden=true`, `ssid=ROGC Classroom` with its space, and a psk
|
||||
containing `#` intact, at 0600 root:root with no `connection.permissions`.
|
||||
`tests/test-classroom-wifi-adopt.sh` drives the whole hand-over against
|
||||
stubbed tools and asserts the ordering, the rollback and the managed
|
||||
state.
|
||||
|
||||
**The prayer-room laptop must not be migrated again.** Its stanza is
|
||||
already gone, so `--adopt` reports "nothing to adopt" and exits 0 without
|
||||
touching anything; there is a test for exactly that.
|
||||
|
||||
After the migration the panel shows the connection at the next login, the
|
||||
room can scan, and the credential protection below applies to it like any
|
||||
other system connection.
|
||||
|
||||
Reference in New Issue
Block a user