Hier ist eine Lösung, die für mich funktioniert. Mein /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
Und /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; }'
Ich bekomme dieses Verhalten:
$ 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$
Die erste Zeile, die dem Standardwert pam.d/sudo
hinzugefügt wird ruft pam_exec
auf und überspringt bei Erfolg den nächsten Eintrag. Die zweite Zeile verweigert den Zugriff einfach bedingungslos.
In /tmp/test-pam
Ich rufe last
an um die IP-Adresse zu erhalten, die dem TTY zugeordnet ist, von dem aus pam aufgerufen wurde. ${PAM_TTY#/dev/}
entfernt /dev/
vom Anfang des Werts, weil last
erkennt nicht den vollständigen Gerätepfad. Die -i
Flag macht last
entweder die IP-Adresse oder den Platzhalter 0.0.0.0
anzeigen wenn es keine IP-Adresse gibt; standardmäßig zeigt es einen Info-String, der viel schwieriger zu überprüfen ist. Aus diesem Grund habe ich auch last
verwendet statt who
oder w
; diese haben keine ähnliche Option. Die -p now
Option ist nicht unbedingt erforderlich, da wir awk
sehen werden prüft nur die erste Ausgabezeile, schränkt aber last
ein um nur Benutzer anzuzeigen, die derzeit angemeldet sind.
Die awk
Der Befehl prüft nur die erste Zeile und ob das dritte Feld nicht 0.0.0.0
ist es wird mit einem Fehler beendet. Da dies der letzte Befehl in /tmp/test-pam
ist , wird der Exit-Code von awk zum Exit-Code für das Skript.
Auf meinem System ist keiner der Tests, die Sie versucht haben, in Ihrem deny-ssh-user.sh
würde funktionieren. Wenn Sie env > /tmp/test-pam.log
eingeben Oben in Ihrem Skript sehen Sie, dass die Umgebung entfernt wurde, sodass keine Ihrer SSH_FOO-Variablen festgelegt wird. Und $PPID könnte auf eine beliebige Anzahl von Prozessen zeigen. Führen Sie beispielsweise perl -e 'system("sudo cat /etc/passwd")'
aus und sehen Sie, dass sich $PPID auf perl
bezieht verarbeiten.
Dies ist Arch Linux, Kernel 4.16.11-1-ARCH
, falls es darauf ankommt. Ich glaube aber nicht, dass es so sein sollte.
Nun, es stellt sich heraus, dass ich eigentlich ein Idiot bin, der pam_exec.so
-Modul ist vollkommen in Ordnung, um PAM-Bedingungen zu erstellen.
Tim Smith hat richtig eingeschätzt, dass beide Tests in meinem /etc/security/deny-ssh-user.sh
liegen -Skript haben die Variable SSH_SESSION
NIE gesetzt zu wahr. Ich habe das nicht berücksichtigt, weil das Skript in einer normalen Shell funktioniert, aber der Umgebungskontext entfernt wird, wenn es von pam_exec.so
ausgeführt wird .
Am Ende habe ich das Skript umgeschrieben, um den last
zu verwenden Dienstprogramm genau wie sein Beispiel, aber ich musste einiges davon ändern, weil die Schalter für last
unterscheiden sich von Arch Linux zu RedHat.
Hier ist das überarbeitete Skript unter /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
Inhalt von /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
....