Berikut adalah solusi yang bekerja untuk saya. /etc/pam.d/sudo saya :
#%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
Dan /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; }'
Saya mendapatkan perilaku ini:
$ 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$
Baris pertama ditambahkan ke pam.d/sudo default memanggil pam_exec dan, jika berhasil, lewati entri berikutnya. Baris kedua hanya menolak akses tanpa syarat.
Di /tmp/test-pam Saya memanggil last untuk mendapatkan alamat IP yang terkait dengan pam TTY yang dipanggil. ${PAM_TTY#/dev/} menghapus /dev/ dari depan nilai, karena last tidak mengenali jalur perangkat lengkap. -i bendera membuat last tampilkan alamat IP atau placeholder 0.0.0.0 jika tidak ada alamat IP; secara default ini menunjukkan string info yang jauh lebih sulit untuk diperiksa. Ini juga mengapa saya menggunakan last bukannya who atau w; mereka tidak memiliki opsi serupa. -p now opsi tidak sepenuhnya diperlukan, seperti yang akan kita lihat awk hanya memeriksa baris keluaran pertama, tetapi membatasi last untuk menampilkan hanya pengguna yang saat ini masuk.
awk perintah hanya memeriksa baris pertama, dan jika kolom ketiga bukan 0.0.0.0 itu keluar dengan kesalahan. Karena ini adalah perintah terakhir di /tmp/test-pam , kode keluar awk menjadi kode keluar untuk skrip.
Di sistem saya, tidak ada tes yang Anda coba di deny-ssh-user.sh Anda akan berhasil. Jika Anda memasukkan env > /tmp/test-pam.log di bagian atas skrip Anda, Anda akan melihat bahwa lingkungan telah dihapus, sehingga tidak ada variabel SSH_FOO Anda yang akan disetel. Dan $PPID dapat menunjuk ke sejumlah proses. Misalnya, jalankan perl -e 'system("sudo cat /etc/passwd")' dan lihat bahwa $PPID merujuk ke perl proses.
Ini adalah Arch Linux, kernel 4.16.11-1-ARCH , jika itu penting. Saya pikir itu tidak seharusnya.
Yah ternyata saya sebenarnya idiot, pam_exec.so modul sangat baik untuk membuat persyaratan PAM.
Tim Smith benar dalam menilai kedua tes di /etc/security/deny-ssh-user.sh saya skrip TIDAK PERNAH menyetel variabel SSH_SESSION untuk benar. Saya tidak mempertimbangkannya karena skrip bekerja di shell normal, tetapi konteks lingkungan dihapus saat dijalankan oleh pam_exec.so .
Saya akhirnya menulis ulang skrip untuk menggunakan last utilitas seperti contohnya, namun saya harus mengubahnya karena beralih ke last berbeda dari Arch Linux ke RedHat.
Ini skrip yang direvisi di /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
Isi dari /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
....