Služba VPN selhává na EXEC: porovnejte unit, binárku a sudoers
Selhání v kroku EXEC znamená, že systemd nedokázal spustit binárku. Než cokoli upravíte, porovnejte cestu v unitu, nainstalovanou cestu a oprávnění v sudoers.
Včera tunel fungoval a dnes ráno je unit mrtvý s Failed at step EXEC spawning /usr/local/bin/vpnclient v journalu. Přihlašovací údaje, trasy ani účet do té věty nikdy nevstupují. systemd přeložil ExecStart na cestu, požádal jádro o její spuštění a jádro odmítlo — nejčastěji proto, že na dané cestě nic není nebo soubor není spustitelný. Berte závadu jako problém souboru a argv, dokud analyzovaný příkaz neprokáže opak.
Proč EXEC selhává dřív, než začne autentizace
systemd nespouští ExecStart přes shell. Vytvoří fork, sestaví z řádku vektor argumentů a zavolá execve na první prvek. Pokud toto volání selže, služba se nikdy nedostane k vlastnímu kódu klienta VPN, takže žádné úpravy profilu ani kontrola přihlašovacích údajů nepomohou.
Stavový kód odděluje tuto rodinu od běžných pádů. Unit, který skončí se status=203/EXEC, nikdy nespustil proces; unit, který se spustí a poté skončí se status=1 mohl selhat při autentizaci, DNS nebo směrování. Přečtěte kód dřív než log klienta, protože v prvním případě bude log klienta prázdný.
Cesta v journalu je ta, kterou použil systemd, ne nutně ta, kterou jste upravili. Drop-in soubory a výstup generátoru mohou přepsat soubor dodavatele a zastaralý daemon-reload nechává starý řádek v paměti. Proto je první diagnostikou zeptat se systemd, co považuje za příkaz, místo otevírání souboru, o kterém si pamatujete, že jste ho měnili.
Tři místa, kde je zapsaná cesta k binárce
Klient VPN nainstalovaný z distribučního balíčku, skriptu dodavatele a tarballu vydání může skončit ve třech různých prefixech. Unit, pravidlo oprávnění a instalátor každý zaznamenal jeden z těchto prefixů a závada se objeví, když se dva ze tří neshodují.
| Record | Common value | How to read it |
|---|---|---|
| Unit or drop-in | /usr/local/bin/vpnclient | systemctl cat vpnclient.service |
| Installed binary | /usr/bin/vpnclient | command -v vpnclient, then ls -l the result |
| Sudoers grant | /opt/vpnclient/bin/vpnclient | sudo grep -r vpnclient /etc/sudoers.d/ |
Konkrétní nesoulad vypadá takto: skript dodavatele instaluje do /usr/local/bin, tarball byl rozbalen pod /opt a unit stále uvádí starou cestu /usr/bin z předchozího balíčku. Existuje jen jeden z těchto souborů a málokdy je to ten v ExecStart.
Než změníte kterýkoli ze souborů, rozhodněte, která cesta je kanonická. Pokud binárku vlastní distribuční balíček, kanonická je cesta balíčku a unit ji má následovat. Pokud ji vlastní skript dodavatele, platí stejné pravidlo pro prefix dodavatele. Kopírování binárky mezi prefixy vytváří dvě kopie, které se při další aktualizaci rozejdou.
Když se z citovaného příkazu stane název souboru
Druhý režim selhání se skrývá za stejným řádkem v journalu. Někdo zapíše do unitu toto a očekává, že se klient při startu připojí:
ExecStart=/usr/bin/"vpnclient connect office"systemd rozdělí hodnotu na slova, takže první slovo se stane /usr/bin/vpnclient connect office a uvozovky se odstraní jako syntaxe seskupení. Jádro pak hledá soubor, jehož název obsahuje mezery, a takový neexistuje. Chyba je stejná jako u chybějící binárky, i když je binárka nainstalovaná.
Podporovanou formou je skutečný spustitelný soubor následovaný samostatnými argumenty, například ExecStart=/usr/bin/vpnclient connect office. Pokud pracovní postup opravdu potřebuje rouru nebo řetěz, dejte ho do skriptu a zavolejte skript, protože ExecStart nemá &&, nemá roury ani glob expanzi.
Opravte unit, ne souborový systém
Lákavá oprava je symbolický odkaz z očekávané cesty na skutečnou binárku. Funguje, dokud se balíček neaktualizuje a odkaz nezačne ukazovat na odstraněný soubor, nebo dokud se štítek SELinux přestane shodovat s cílem. Raději upravte unit pomocí drop-in, aby soubor dodavatele zůstal nedotčený a aktualizace zůstaly předvídatelné.
Pravidlo oprávnění musí odpovídat stejné cestě i stejným podpříkazům. Záznam v sudoers pro /usr/local/bin/vpnclient neopravňuje /usr/bin/vpnclient a záznam, který povoluje jakýkoli argument, umožní libovolnému místnímu procesu překonfigurovat nebo zastavit tunel. Dejte unitu obě potřebná slovesa a ponechte demontáž mimo něj, pokud zastavení služby už zavírá rozhraní.
Tady se porovnání vyplatí: unit, databáze balíčků i sudoers by měly uvádět jednu cestu. Když se tak stane, chyba EXEC zmizí bez restartu a bez kopie binárky na třetím místě.
Dokažte analyzovaný příkaz před restartem
sudo systemctl daemon-reload
sudo systemctl cat vpnclient.service
systemctl show -p ExecStart vpnclient.service
systemd-analyze verify /etc/systemd/system/vpnclient.service
sudo systemctl restart vpnclient.service
systemctl status vpnclient.service --no-pagersystemctl show je rozhodující výstup, protože vypisuje argv, které systemd skutečně analyzoval, včetně případného drop-in. systemd-analyze verify zachytí chybějící nebo nespustitelnou cestu ještě před restartem a stavový příkaz po restartu řekne, zda proces nyní existuje.
Pokud se unit spustí a potom selže, opustili jste rodinu EXEC a vstoupili do vlastního zpracování chyb klienta. Hledejte v journalu zprávu klienta, ne další selhání execve. Držte diff unitu a diff sudoers společně v záznamu změny, aby příští aktualizace tiše nevrátila rozdělenou cestu.