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