Zde je řešení, které pro mě funguje. Můj /etc/pam.d/sudo :
#%PAM-1.0
auth [success=1] pam_exec.so /tmp/test-pam
auth required pam_deny.so
auth include system-auth
account include system-auth
session include system-auth
A /tmp/test-pam :
#! /bin/bash
/bin/last -i -p now ${PAM_TTY#/dev/} | \
/bin/awk 'NR==1 { if ($3 != "0.0.0.0") exit 9; exit 0; }'
Chápu toto chování:
$ sudo date
[sudo] password for jdoe:
Thu Jun 28 23:51:58 MDT 2018
$ ssh localhost
Last login: Thu Jun 28 23:40:23 2018 from ::1
valli$ sudo date
/tmp/test-pam failed: exit code 9
[sudo] password for jdoe:
sudo: PAM authentication error: System error
valli$
První řádek přidán k výchozímu pam.d/sudo volání pam_exec a pokud uspěje, přeskočí další položku. Druhý řádek pouze bezpodmínečně odepře přístup.
V /tmp/test-pam Volám last získat IP adresu spojenou s TTY pam byla vyvolána. ${PAM_TTY#/dev/} odstraní /dev/ od začátku hodnoty, protože last nerozpozná celou cestu k zařízení. -i příznak dělá last zobrazit buď IP adresu, nebo zástupný symbol 0.0.0.0 pokud neexistuje žádná IP adresa; ve výchozím nastavení zobrazuje informační řetězec, který je mnohem obtížnější zkontrolovat. To je také důvod, proč jsem použil last místo who nebo w; ti podobnou možnost nemají. -p now volba není nezbytně nutná, jak uvidíme awk kontroluje pouze první řádek výstupu, ale omezuje last zobrazit pouze uživatele, kteří jsou aktuálně přihlášeni.
awk příkaz pouze zkontroluje první řádek a pokud třetí pole není 0.0.0.0 ukončí se s chybou. Protože toto je poslední příkaz v /tmp/test-pam , výstupní kód awk se stane výstupním kódem pro skript.
V mém systému žádný z testů, které jste zkoušeli v deny-ssh-user.sh by fungovalo. Pokud zadáte env > /tmp/test-pam.log v horní části skriptu uvidíte, že prostředí bylo odstraněno, takže nebude nastavena žádná z vašich proměnných SSH_FOO. A $PPID může ukazovat na libovolný počet procesů. Spusťte například perl -e 'system("sudo cat /etc/passwd")' a uvidíte, že $PPID odkazuje na perl proces.
Toto je Arch Linux, jádro 4.16.11-1-ARCH , v případě, že na tom záleží. Nemyslím si však, že by mělo.
No, ukázalo se, že jsem vlastně idiot, pam_exec.so modul je naprosto v pořádku pro vytváření podmínek PAM.
Tim Smith měl pravdu, když vyhodnotil oba testy v mém /etc/security/deny-ssh-user.sh skript NIKDY nenastavoval proměnnou SSH_SESSION na pravdu. Nebral jsem to v úvahu, protože skript funguje v normálním prostředí, ale kontext prostředí je při spuštění pomocí pam_exec.so odstraněn .
Nakonec jsem skript přepsal tak, aby používal last utility stejně jako jeho příklad, ale některé jsem musel změnit, protože přepínače pro last se liší od Arch Linuxu a RedHat.
Zde je upravený skript na /etc/security/deny-ssh-user.sh:
#!/bin/bash
# Returns 1 if the user is logged in through SSH
# Returns 0 if the user is not logged in through SSH
SSH_SESSION=false
function isSshSession {
local terminal="${1}"
if $(/usr/bin/last -i |
/usr/bin/grep "${terminal}" |
/usr/bin/grep 'still logged in' |
/usr/bin/awk '{print $3}' |
/usr/bin/grep -q --invert-match '0\.0\.0\.0'); then
echo true
else
echo false
fi
}
function stripTerminal {
local terminal="${1}"
# PAM_TTY is in the form /dev/pts/X
# Last utility displays TTY in the form pts/x
# Returns the first five characters stripped from TTY
echo "${terminal:5}"
}
lastTerminal=$( stripTerminal "${PAM_TTY}")
SSH_SESSION=$(isSshSession "${lastTerminal}")
if "${SSH_SESSION}"; then
exit 1
else
exit 0
fi
Obsah /etc/pam.d/sudo
....
auth [success=ok default=1] pam_exec.so /etc/security/deny-ssh-user.sh
auth sufficient pam_module_to_skip.so
....