ここに私のために働く解決策があります。私の /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
そして /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; }'
私はこの動作を取得します:
$ 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$
デフォルトの pam.d/sudo
に追加された最初の行 pam_exec
を呼び出します 成功した場合は、次のエントリをスキップします。 2 行目は無条件にアクセスを拒否するだけです。
/tmp/test-pam
で last
と呼びます pam が呼び出された TTY に関連付けられた IP アドレスを取得します。 ${PAM_TTY#/dev/}
/dev/
を削除します last
であるため、値の先頭から 完全なデバイス パスを認識しません。 -i
フラグは last
になります IP アドレスまたはプレースホルダー 0.0.0.0
のいずれかを表示します IP アドレスがない場合。デフォルトでは、確認がはるかに難しい情報文字列が表示されます。これが last
を使用した理由でもあります who
の代わりに または w
;それらには同様のオプションがありません。 -p now
awk
が表示されるため、オプションは厳密には必要ありません。 出力の最初の行のみをチェックしていますが、 last
を制限しています 現在ログインしているユーザーのみを表示します。
awk
コマンドは最初の行をチェックするだけで、3 番目のフィールドが 0.0.0.0
でない場合 エラーで終了します。これは /tmp/test-pam
の最後のコマンドなので 、awk の終了コードがスクリプトの終了コードになります。
私のシステムでは、あなたが deny-ssh-user.sh
で試していたテストはどれもありませんでした 動作します。 env > /tmp/test-pam.log
を入れると スクリプトの先頭で、環境が削除されていることがわかります。そのため、SSH_FOO 変数は設定されません。 $PPID は、任意の数のプロセスを指すことができます。たとえば、perl -e 'system("sudo cat /etc/passwd")'
を実行します。 $PPID が perl
を参照していることを確認します
これは Arch Linux、カーネル 4.16.11-1-ARCH
です 、重要な場合に備えて。でも、そうすべきではないと思います。
pam_exec.so
というのは、実は私がバカなのです。 モジュールは、PAM 条件を作成するのに最適です。
私の /etc/security/deny-ssh-user.sh
での両方のテストの評価において、Tim Smith は正しかった スクリプトは変数 SSH_SESSION
を決して設定しませんでした 真に。スクリプトは通常のシェルで動作するため、考慮していませんでしたが、pam_exec.so
で実行すると環境コンテキストが削除されます。 .
last
を使用するようにスクリプトを書き直すことになりました ユーティリティは彼の例と同じですが、 last
のスイッチのため、一部を変更する必要がありました Arch Linux と RedHat では異なります。
/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
/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
....