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
....