Linux 中的 PAM:如果远程/外部身份验证数据库返回负面响应,是否有办法跳过本地身份验证?

Linux 中的 PAM:如果远程/外部身份验证数据库返回负面响应,是否有办法跳过本地身份验证?

亲爱的系统修补者们,

一位管理员朋友问了我以下问题:

在许多网络元素和服务器上,他使用针对 TACACS+ 服务器的远程身份验证。在某些此类专有设备上,如果远程方法返回“身份验证服务器不可用”(无法访问,超时),身份验证只会询问本地身份验证数据库。如果远程身份验证服务器可用,并返回否定响应,则有问题的盒子会按表面意义接受这一点,并且不会尝试针对本地用户数据库进行身份验证。

现在...在基于 Linux 的机器上,他想实现相同的行为。但他似乎无法做到。Linux 操作系统首先尝试远程身份验证,但在收到明确的否定响应(服务器响应“身份验证失败,这些不是有效凭据”)后,它继续尝试本地数据库。

我了解到远程 TACACS+ 身份验证由一个名为 pam_tacplus 的 PAM 模块安排。阅读有关 PAM 的一般信息后,我似乎意识到 pam_tacplus 并不是罪魁祸首。相反,观察到的行为只是 PAM 整体的工作方式。如果是这样,直接的解决方案可能必须涉及向 PAM 代码库添加可配置的全局选项,并且可能添加特定的 PAM 配置文件关键字/语法,以将行为修改为所需的方向。

欢迎就此主题发表进一步的评论:-)

答案1

...根据进一步阅读,让我提出一个答案。任何补充或更正当然都热烈欢迎。

首先我发现这个已经很久了PAM 简介。这些年来,它的敏锐才智可能并未消失。

如果我仔细查看,auth 模块的返回值是记录在官方 linux-pam 文档中

在列表中,我可以看到一个名为 PAM_AUTHINFO_UNAVAIL 的有希望的 retval。

实际上定义在libpam/include/安全/_pam_types.h

#define PAM_SUCCESS 0
#define PAM_AUTHINFO_UNAVAIL 9
#define _PAM_RETURN_VALUES 32 

PAM_AUTHINFO_UNAVAIL 的定义似乎存在冲突libpam/include/security/_pam_compat.h

# define PAM_AUTHINFO_UNAVAIL     12

—— 或许可以忽略。

源文件libpam/pam_dispatch.c 包含一个名为 _pam_dispatch_aux() 的关键函数实际上遍历已注册身份验证模块的堆栈,并根据它们的返回值采取行动。而且,事实证明它并没有直接根据“retval”做很多事情,可能包含PAM_AUTHINFO_UNAVAIL。它确实直接响应某些特定的“内部特殊用途”值retval,但没有对的特殊处理PAM_AUTHINFO_UNAVAILretval不是_pam_dispatch_aux()其自身的返回值:而是retval只是在 for(;;) 循环内声明的局部变量,该循环遍历已注册身份验证模块的堆栈,其中块局部retval收集特定模块的返回值。堆栈遍历循环实际上根据其他变量做出重要决定:其中一个派生,称为action,另一个是impression模块通过引用“返回”的结构成员。所以也许它毕竟可能受到模块自身代码的影响?

事实上,它action是从“动作查找表”中获取的, 索引retval——啊哈!

action = h->actions[cached_retval];

动作表是否由模块定义?但是,如果 _PAM_ACTION_* 宏在 #defined 中定义,那么如何定义libpam/pam_private.h

事实证明,actions[] 表是以通用方式初始化通过一个函数调用_pam_parse_conf_file()libpam/pam_handlers.c它执行直接字符串比较(匹配)诸如 requiredrequisiteoptional、等关键字sufficient

并且,整个表目前有 32 个位置(参见上面引用的宏定义),批发初始化在解析特定模块的配置条目之前,将其更改为 _PAM_ACTION_UNDEF。然后,各个“强度关键字”将各个关键字重新映射retval到特定的所需操作。

因此:从中获取灵感似乎是相当明显的:

} else if (!strcasecmp("required", tok)) {
    D(("*PAM_F_REQUIRED*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_OK;
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;
    actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
    _pam_set_default_control(actions, _PAM_ACTION_BAD);
} else if (!strcasecmp("sufficient", tok)) {
    D(("*PAM_F_SUFFICIENT*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_DONE;
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_DONE;
    _pam_set_default_control(actions, _PAM_ACTION_IGNORE);
}

并添加类似

} else if (!strcasecmp("reqd_if_avail", tok)) {
    D(("*PAM_F_REQD_IF_AVAIL*"));
    actions[PAM_SUCCESS] = _PAM_ACTION_OK;
    actions[PAM_AUTHINFO_UNAVAIL] = _PAM_ACTION_IGNORE; // !!!!!!!!!!
    actions[PAM_NEW_AUTHTOK_REQD] = _PAM_ACTION_OK;     // ?
    actions[PAM_IGNORE] = _PAM_ACTION_IGNORE;
    _pam_set_default_control(actions, _PAM_ACTION_BAD); // !!!
}

显然还有 pam_tacplus帮助我们走上这条道路

如果现有的 PAM 配置文件语法能够实现相同的效果,而无需破解源代码,那当然很好。

相关内容