3.2. 对应用程序的期望

3.2.1. 对话功能

#include <security/pam_appl.h>
struct pam_message {
    int msg_style;
    const char *msg;
};

struct pam_response {
    char *resp;
    int resp_retcode;
};

struct pam_conv {
    int (*conv)(int num_msg, const struct pam_message **msg,
                struct pam_response **resp, void *appdata_ptr);
    void *appdata_ptr;
};

3.2.1.1. DESCRIPTION

PAM 库使用应用程序定义的回调来允许已加载的模块与应用程序之间的直接通信。该回调由在事务开始时传递给 pam_start(3)的* struct pam_conv *指定。

当模块调用引用的 conv()函数时,参数* appdata_ptr *被设置为该结构的第二个元素。

调用 conv()的其他参数涉及模块和应用程序交换的信息。也就是说,* num_msg 保持指针数组 msg 的长度。成功返回后,指针 resp 指向 pam_response 结构的数组,其中包含应用程序提供的文本。该结构的 resp_retcode 成员未使用,应设置为零。调用者有责任使用 free(3)释放此数组和响应本身。注意,* resp struct pam_response *数组,而不是指针数组。

响应数始终等于* num_msg *对话函数参数。这确实要求在每次调用会话函数之后,响应数组都必须是 free(3)。响应的索引直接对应于 pam_message 数组中的提示索引。

失败时,对话功能应释放其已分配的所有资源,并返回 sched 义的 PAM 错误代码之一。

每个消息可以具有四种类型之一,由* struct pam_message msg_style *成员指定:

  • PAM_PROMPT_ECHO_OFF

    • 获取字符串而不回显任何文本。
  • PAM_PROMPT_ECHO_ON

    • 在回显文本的同时获取字符串。
  • PAM_ERROR_MSG

    • 显示错误信息。
  • PAM_TEXT_INFO

    • 显示一些 Literals。

拥有消息数组的意义在于,有可能在一次来自模块的调用中将许多东西传递给应用程序。对于应用程序来说,关联的事物一下子出现也很方便:基于 Windows 的应用程序可以立即呈现一个带有许多消息/提示的表单。

顺便说一句,值得注意的是,Linux-PAM 处理 const struct pam_message msg 对话函数参数的方式与 Solaris 的 PAM(以及派生的产品,包括 HP/UX)之间存在差异.?).Linux-PAM 将 msg 参数解释为完全等同于以下原型 const struct struct pam_message * msg [](从本质上讲,它与熟悉的 main()函数的 argv 参数的常用原型一致:char argv;和 char * argv [])。换句话说,Linux-PAM 将 msg 参数解释为指向 num_msg 只读数组“ struct pam_message”的指针的指针。 Solaris 的 PAM 实现将此参数解释为指向 num_msg pam_message 结构数组的指针。幸运的是,对于大多数模块/应用程序开发人员而言,当 num_msg 的值为 1 时,这两个定义是完全等效的。不幸的是,随便将此数字增加到两个会导致意外的兼容性问题。

试图维持两种 PAM 实现与源代码级兼容性的两个已知模块编写器变通办法有何价值:

  • 永远不要调用 num_msg 大于 1 的对话函数。

  • 将 msg 设置为双重引用,以便两种类型的对话功能都可以找到消息。也就是说,使

msg[n] = & (( *msg )[n])

3.2.1.2. 返回值

  • PAM_BUF_ERR

    • 内存缓冲区错误。
  • PAM_CONV_ERR

    • 通话失败。该应用程序不应设置** resp *。
  • PAM_SUCCESS

    • Success.