使用 pam_exec.so 进行条件输入

使用 pam_exec.so 进行条件输入

我正在 RedHat 7.5 上测试 PAM 场景

pam 模块 pam_succeed_if.so 看起来像是 PAM 必须提供的最基本级别的条件测试,但它不能满足我的需求。您只能在 user、uid、gid、shell、home、ruser、rhost、tty 和 service 字段上创建测试。

在我的情况下,我确实想基于“rhost”字段进行测试,但是将模块投入调试后,我发现 rhost 字段未设置。

我的目标是只运行 PAM 模块/etc/pam.d/sudo如果用户在本地登录到计算机。如果我们可以检测到用户是通过 SSH 登录的,那么我想跳过该模块。我实际上提出了 3 个我认为可行的不同想法,但最终都失败了。

我将分享一些最终失败的解决方案

使用 pam_exec.so 进行条件输入

我想在我想有条件跳过的 pam 模块顶部添加以下 pam 条目:

auth    [success=ok default=1]    pam_exec.so /etc/security/deny-ssh-user.sh

/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
if [ -n "${SSH_CLIENT}" ] || [ -n "${SSH_TTY}" ] || [ -n "${SSH_CONNECTION}" ]; then
    SSH_SESSION=true
else
    case $(ps -o comm= -p $PPID) in
        sshd|*/sshd) SSH_SESSION=true;;
    esac
fi

if "${SSH_SESSION}"; then
    exit 1
else
    exit 0
fi

我已经浏览了 pam_exec.so 的源代码https://github.com/linux-pam/linux-pam/blob/master/modules/pam_exec/pam_exec.c令人惊讶的是,无论脚本的退出代码如何,它总是返回 PAM_SUCCESS。我无法让脚本导致 pam_exec 模块返回 PAM_SERVICE_ERR、PAM_SYSTEM_ERR 或 PAM_IGNORE。

使用 pam_access.so 进行条件输入

再次,我在要有条件跳过的 pam 模块顶部添加以下 pam 条目

auth    [success=ok perm_denied=1]    pam_access.so    accessfile=/etc/security/ssh-sudo-access.conf noaudit

/etc/security/ssh-sudo-access.conf 的内容

+:ALL:localhost 127.0.0.1 
-:ALL:ALL

哇,超级干净吧?如果您在本地登录,它将返回成功,并拒绝其他一切。好吧,不。事实证明,当 pam_access.so 模块投入调试时,它不知道远程主机,只知道正在使用的终端。因此 pam_access 实际上无法阻止远程主机的访问。

这是令人气愤的一天,我从字面上阅读源代码,只是为了找出我必须施放什么黑魔法,这样我才能跳过 PAM 模块。

答案1

这是一个适合我的解决方案。我的/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,如果成功,则跳过下一个条目。第二行只是无条件拒绝访问。

/tmp/test-pam我调用中last获取与调用 TTY pam 关联的 IP 地址。从值的前面${PAM_TTY#/dev/}删除,因为无法识别完整的设备路径。该标志使显示 IP 地址或占位符(如果没有 IP 地址);默认情况下,它显示一个更难检查的信息字符串。这也是我使用or代替的原因;那些没有类似的选项。该选项并不是绝对必要的,因为我们将看到仅检查输出的第一行,但它限制为仅显示当前登录的用户。/dev/last-ilast0.0.0.0lastwhow-p nowawklast

awk命令仅检查第一行,如果第三个字段不是,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,以防万一。但我认为不应该。

答案2

事实证明我实际上是个白痴,该pam_exec.so模块非常适合创建 PAM 条件。

蒂姆·史密斯(Tim Smith)的评估是正确的,我的/etc/security/deny-ssh-user.sh脚本中的两个测试从未将变量设置SSH_SESSION为 true。我没有考虑到这一点,因为该脚本在普通 shell 中工作,但在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
....

相关内容