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]>
11 KiB
Classroom networking
Ethernet remains the normal classroom connection. The package also installs and enables NetworkManager so an administrator can add Wi-Fi when a room needs it; there is no classroom Wi-Fi screen and no network name or password in the package.
Add Wi-Fi
From a terminal or SSH session, run:
sudo nmtui
Choose Activate a connection, select the church Wi-Fi network, enter its password, and activate it. NetworkManager saves the connection as a system connection and reconnects it automatically after reboot.
Useful checks:
nmcli device status
nmcli connection show
systemctl status NetworkManager
There is nothing to configure on a computer without Wi-Fi hardware. NetworkManager starts normally, sees no Wi-Fi device, and Ethernet continues to work.
Existing Ethernet configuration
Do not remove or rewrite /etc/network/interfaces as part of this procedure.
Debian Trixie's NetworkManager configuration uses the ifupdown plugin with
managed=false, so any Ethernet interface declared there remains under
ifupdown's control. NetworkManager manages other interfaces, including Wi-Fi.
This preserves an existing static or ifupdown Ethernet setup.
The package disables NetworkManager-wait-online.service; no classroom
feature is allowed to hold boot waiting for Wi-Fi or Internet access. Saved
connections still reconnect automatically.
Wi-Fi passwords, and who may see them
These are shared computers in rooms full of people. The classroom account has to be able to USE the church Wi-Fi and must never be able to READ its password. In a stock Plasma desktop those two are much closer together than they look.
Provision Wi-Fi with classroom-wifi, as root. Not from the desktop.
classroom-wifi "Church Wi-Fi" # prompts, never echoes, never in ps
classroom-wifi --list
classroom-wifi --forget "Old Network"
This is a requirement, not a convenience. A wireless network added from
the desktop becomes a user connection: NetworkManager records
connection.permissions naming whoever added it, and Debian allows that
user to read its secrets with no authentication at all —
org.freedesktop.NetworkManager.settings.modify.own ships as yes for an
active session. Plasma's applet then offers Show Network's QR Code on
every saved wireless connection, and that QR code contains the pre-shared
key. So a password typed in at the desktop is readable by the next person
to sit down.
classroom-wifi creates a system connection instead: no
connection.permissions, secrets in a root-only file
(/etc/NetworkManager/system-connections/*.nmconnection, 0600 root:root),
psk-flags=0 so nothing lands in a login keyring. Every account can use
it, and NetworkManager reconnects at boot on its own — no teacher ever
re-enters it.
What is refused, and what is deliberately not
49-ekklesia-classroom-network.rules answers at NetworkManager rather
than in a menu, because hiding buttons is not a control: the applet's
Show Network's QR Code and Configure… are contextual actions that do
not consult the Kiosk key which hides its settings button.
Refused for classroom: settings.modify.own, settings.modify.system,
wifi.share.protected, wifi.share.open, settings.modify.hostname,
settings.modify.global-dns, reload, checkpoint-rollback.
Left alone on purpose: network-control, wifi.scan,
enable-disable-network, enable-disable-wifi. None of them returns a
secret, and they are what connecting and seeing a network are made of. A
rule that protected a password by taking the room off the internet would
not be a trade this room can make. Automatic reconnection does not go
through polkit at all — NetworkManager does it as root — so nothing here
can stop the room coming back after a reboot.
An administrator's own account and root are untouched. To lift any of it
for maintenance, drop a file of the same name into
/etc/polkit-1/rules.d/, which polkit reads first.
A Wi-Fi the Debian installer set up
Symptom: the internet works, Chrome loads pages, and the panel insists there is no connection. Scanning finds nothing either.
Both are true at once, and they have one cause. If the installer was
given the Wi-Fi, it wrote the network into /etc/network/interfaces.
ifupdown brings that up with its own wpa_supplicant and dhcpcd, which
is the working internet. NetworkManager ships here with
plugins=ifupdown and [ifupdown] managed=false, so an interface named
in that file is marked unmanaged — and an unmanaged device is not a
radio NetworkManager will report on or scan with.
Measured on the Bible study laptop:
$ nmcli device status
wlp2s0 wifi unmanaged --
$ nmcli networking connectivity
none # while curl fetched fine
$ nmcli device wifi list
SSID SIGNAL # nothing, and the radio is enabled
managed=false stays. It is what keeps a tower's static Ethernet under
ifupdown's control where an administrator put it. Only a wireless
interface is moved.
Moving it, while watching
This is never done by an upgrade. It moves a machine's only link between
two managers, and the machine it could strand is a laptop in a locked
room. classroom-migrate only looks and says what it found. An
administrator does the rest, over SSH, watching:
classroom-wifi --check # who owns it; changes nothing
classroom-wifi --adopt --dry-run # what would change; changes nothing
classroom-wifi --adopt # do it
classroom-wifi --rollback # undo it, at any time afterwards
--adopt creates a NetworkManager system connection from the SSID
and key already in that file — so the password never leaves the machine,
is never printed, and lands in a 0600 root-only file with psk-flags=0,
exactly as classroom-wifi provisions any other network. The stanza is
then commented out, the interface handed over, and the result checked:
the connection must be active on that interface and the machine must
really fetch something. Checking only "is the machine online" would pass
on a machine with a second link while the Wi-Fi sat dead.
If any of that fails — including a command that is not installed, or an
interrupt — the original file is put back and ifupdown gets the interface
again. It refuses to start at all if ifdown/ifup are missing, because
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.
Recovery when there is no network at all
There is deliberately no teacher-facing "join a network" dialog in this
release. Anything that lets the room add a connection also lets the room
own it, and an owned connection is a readable one. Recovery is an
administrator running classroom-wifi over SSH, or at the machine
through the maintenance terminal chord. If a room ever needs to join a
network unattended, that workflow has to be designed so the connection it
creates still belongs to the machine — not bolted on by relaxing the rule
above.