2.1. 获取和设置 PAM_ITEM 和数据
首先,我们介绍了* Linux-PAM 库和 Linux-PAM *感知应用程序对模块的期望。本质上,这是libpam.*
库。
2.1.1. 设置模块内部数据
#include <security/pam_modules.h>
int pam_set_data(
pamh,
module_data_name,
data,
(*cleanup)(pam_handle_t *pamh, void *data, int error_status));
pam_handle_t *pamh;
const char *module_data_name;
void *data;
void (*cleanup)(pam_handle_t *pamh, void *data, int error_status);
2.1.1.1. DESCRIPTION
pam_set_data
函数将一个对象的指针与* pamh 参数指定的 PAM 上下文中的(希望)唯一字符串 module_data_name *相关联。
PAM 模块可以是可动态加载的对象。通常,此类文件不应包含* static 变量。该函数及其对应的 pam_get_data(3)为模块提供了一种机制,可将某些数据与句柄 pamh 关联。通常,模块将调用pam_set_data
函数以(希望)唯一的 module_data_name 注册一些数据。数据也可以供其他模块使用,但不能被应用程序使用。由于此函数仅存储指向 data *的指针,因此模块不应修改或释放其内容。
函数cleanup()
与* data *相关联,如果非 NULL,则当该数据被覆盖或在调用 pam_end(3)之后被调用。
-
error_status 参数用于向模块指示在清理此数据项时要执行的操作种类。例如,Kerberos 在身份验证阶段创建票证文件,该文件可能与数据项关联。当模块调用 pam_end(3)时, error_status 会携带 pam_authenticate(3)或其他 libpam 函数的返回值。基于此值,Kerberos 模块可以选择删除票证文件( authentication failure *)或将其保留在原位。
-
error_status *可能已与以下两个值之一进行逻辑或运算:
-
PAM_DATA_REPLACE
- 替换数据项时(通过第二次调用
pam_set_data
),将使用此掩码。否则,假定该调用来自 pam_end(3)。
- 替换数据项时(通过第二次调用
-
PAM_DATA_SILENT
- 这表明该进程希望安静地执行
cleanup()
。也就是说,不鼓励向用户发送日志/消息。
- 这表明该进程希望安静地执行
2.1.1.2. 返回值
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_SUCCESS
- 数据已成功存储。
-
PAM_SYSTEM_ERR
- NULL 指针已作为 PAM 句柄提交,或者该函数已由应用程序调用。
2.1.2. 获取模块内部数据
#include <security/pam_modules.h>
int pam_get_data(
pamh,
module_data_name,
data);
const pam_handle_t *pamh;
const char *module_data_name;
const void **data;
2.1.2.1. DESCRIPTION
此函数与 pam_set_data(3)函数一起用于 Management 仅对调用 PAM 模块有意义的模块特定数据。
pam_get_data
函数在* pamh 参数指定的 PAM 上下文中查找与(希望)唯一字符串 module_data_name 关联的对象。成功调用pam_get_data
将导致 data *指向对象。注意,该数据不是副本,应被模块视为常量。
2.1.2.2. 返回值
-
PAM_SUCCESS
- 数据已成功检索。
-
PAM_SYSTEM_ERR
- NULL 指针已作为 PAM 句柄提交,或者该函数已由应用程序调用。
-
PAM_NO_MODULE_DATA
- 找不到模块数据或没有条目,但其值为 NULL。
2.1.3. 设置 PAM 项目
#include <security/pam_modules.h>
int pam_set_item(
pamh,
item_type,
item);
pam_handle_t *pamh;
int item_type;
const void *item;
2.1.3.1. DESCRIPTION
pam_set_item
功能允许应用程序和 PAM 服务模块访问和更新* item_type 的 PAM 信息。为此,将创建 item 参数指向的对象的副本。支持以下 item_type *:
-
PAM_SERVICE
- 服务名称(标识 PAM 功能将用来认证程序的 PAM 堆栈)。
-
PAM_USER
- 将提供身份服务的实体的用户名。也就是说,经过身份验证后,* PAM_USER 会标识使用该服务的本地实体。注意,该值可以通过 PAM 堆栈中的任何模块从某些内容(例如“匿名”)Map 到其他内容(例如“ guest119”)。因此,在每次调用 PAM 函数后,应用程序都应查询 PAM_USER *的值。
-
PAM_USER_PROMPT
- 提示 Importing 用户名时使用的字符串。该字符串的默认值为“ login:”的本地化版本。
-
PAM_TTY
- 终端名称:如果是设备文件,则以
/dev/
作为前缀;对于基于 X 的图形应用程序,此项的值应为* $ DISPLAY *变量。
- 终端名称:如果是设备文件,则以
-
PAM_RUSER
- 请求用户名:本地请求用户的本地名称或远程请求用户的远程用户名称。
通常,应用程序或模块将尝试提供经过最强身份验证的值(本地帐户先于远程帐户)。对该值的信任级别体现在与应用程序关联的实际身份验证堆栈中,因此最终位于系统 Management 员的酌处权。
- PAM_RUSER @ PAM_RHOST 应该始终标识请求用户。在某些情况下, PAM_RUSER *可能为 NULL。在这种情况下,不清楚请求实体是谁。
-
PAM_RHOST
- 请求主机名(* PAM_RUSER 实体正在从中请求服务的机器的主机名)。也就是说 PAM_RUSER @ PAM_RHOST 确实标识了发出请求的用户。在某些应用程序中, PAM_RHOST *可能为 NULL。在这种情况下,不清楚身份验证请求的来源。
-
PAM_AUTHTOK
- 认证令牌(通常是密码)。除 pam_sm_authenticate(3)和 pam_sm_chauthtok(3)外,所有模块功能都应忽略此令牌。在前一个功能中,它用于将最新的身份验证令牌从一个堆叠模块传递到另一个模块。在后一种功能中,令牌用于其他目的。它包含当前活动的身份验证令牌。
-
PAM_OLDAUTHTOK
- 旧的身份验证令牌。除 pam_sm_chauthtok(3)之外的所有模块功能均应忽略此令牌。
-
PAM_CONV
- pam_conv 结构。参见 pam_conv(3)。
以下附加项目特定于 Linux-PAM,不应在可移植应用程序中使用:
-
PAM_FAIL_DELAY
- 用于重定向集中 Management 的故障延迟的函数指针。参见 pam_fail_delay(3)。
-
PAM_XDISPLAY
- X 显示的名称。对于基于 X 的图形应用程序,此项的值应为* $ DISPLAY 变量。此值可以独立于 PAM_TTY *使用,以传递显示名称。
-
PAM_XAUTHDATA
- 指向包含 X 认证数据的结构的指针,该数据需要与* PAM_XDISPLAY *指定的显示器构建连接(如果需要)。请参阅 pam_xauth_data(3)。
-
PAM_AUTHTOK_TYPE
- 默认操作是模块在请求密码时使用以下提示:“ New UNIX password:”和“ Retype UNIX password:”。示例词* UNIX *可以替换为该项目,默认情况下为空。 pam_get_authtok(3)使用此项目。
对于除* PAM_CONV 和 PAM_FAIL_DELAY 之外的所有* item_type , item 是指向\ 终止的字符串的指针。对于 PAM_CONV, item 指向已初始化的 pam_conv 结构。对于 PAM_FAIL_DELAY, item *是函数指针:void (*delay_fn)(int retval, unsigned usec_delay, void *appdata_ptr)
返回到应用程序之前,PAM_AUTHTOK 和 PAM_OLDAUTHTOK 都将被重置。这意味着应用程序无法访问身份验证令牌。
2.1.3.2. 返回值
-
PAM_BAD_ITEM
- 应用程序试图设置一个未定义或不可访问的项目。
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_SUCCESS
- 数据更新成功。
-
PAM_SYSTEM_ERR
- 作为第一个参数传递的* pam_handle_t *无效。
2.1.4. 获取 PAM 项目
#include <security/pam_modules.h>
int pam_get_item(
pamh,
item_type,
item);
const pam_handle_t *pamh;
int item_type;
const void **item;
2.1.4.1. DESCRIPTION
pam_get_item
功能允许应用程序和 PAM 服务模块访问和检索* item_type 的 PAM 信息。成功返回后, item 包含一个指向相应项目值的指针。注意,这是指向实际数据的指针,并且不应被 free()*编辑或覆盖! * item_type *支持以下值:
-
PAM_SERVICE
- 服务名称(标识 PAM 功能将用来认证程序的 PAM 堆栈)。
-
PAM_USER
- 将提供身份服务的实体的用户名。也就是说,经过身份验证后,* PAM_USER 会标识使用该服务的本地实体。注意,该值可以通过 PAM 堆栈中的任何模块从某些内容(例如“匿名”)Map 到其他内容(例如“ guest119”)。因此,在每次调用 PAM 函数后,应用程序都应查询 PAM_USER *的值。
-
PAM_USER_PROMPT
- 提示 Importing 用户名时使用的字符串。该字符串的默认值为“ login:”的本地化版本。
-
PAM_TTY
- 终端名称:如果是设备文件,则以
/dev/
作为前缀;对于基于 X 的图形应用程序,此项的值应为* $ DISPLAY *变量。
- 终端名称:如果是设备文件,则以
-
PAM_RUSER
- 请求用户名:本地请求用户的本地名称或远程请求用户的远程用户名称。
通常,应用程序或模块将尝试提供经过最强身份验证的值(本地帐户先于远程帐户)。对该值的信任级别体现在与应用程序关联的实际身份验证堆栈中,因此最终位于系统 Management 员的酌处权。
- PAM_RUSER @ PAM_RHOST 应该始终标识请求用户。在某些情况下, PAM_RUSER *可能为 NULL。在这种情况下,不清楚请求实体是谁。
-
PAM_RHOST
- 请求主机名(* PAM_RUSER 实体正在从中请求服务的机器的主机名)。也就是说 PAM_RUSER @ PAM_RHOST 确实标识了发出请求的用户。在某些应用程序中, PAM_RHOST *可能为 NULL。在这种情况下,不清楚身份验证请求的来源。
-
PAM_AUTHTOK
- 认证令牌(通常是密码)。除 pam_sm_authenticate(3)和 pam_sm_chauthtok(3)外,所有模块功能都应忽略此令牌。在前一个功能中,它用于将最新的身份验证令牌从一个堆叠模块传递到另一个模块。在后一种功能中,令牌用于其他目的。它包含当前活动的身份验证令牌。
-
PAM_OLDAUTHTOK
- 旧的身份验证令牌。除 pam_sm_chauthtok(3)之外的所有模块功能均应忽略此令牌。
-
PAM_CONV
- pam_conv 结构。参见 pam_conv(3)。
以下附加项目特定于 Linux-PAM,不应在可移植应用程序中使用:
-
PAM_FAIL_DELAY
- 用于重定向集中 Management 的故障延迟的函数指针。参见 pam_fail_delay(3)。
-
PAM_XDISPLAY
- X 显示的名称。对于基于 X 的图形应用程序,此项的值应为* $ DISPLAY 变量。此值可以独立于 PAM_TTY *使用,以传递显示名称。
-
PAM_XAUTHDATA
- 指向包含 X 认证数据的结构的指针,该数据需要与* PAM_XDISPLAY *指定的显示器构建连接(如果需要)。请参阅 pam_xauth_data(3)。
-
PAM_AUTHTOK_TYPE
- 默认操作是模块在请求密码时使用以下提示:“ New UNIX password:”和“ Retype UNIX password:”。示例词* UNIX *可以替换为该项目,默认情况下为空。 pam_get_authtok(3)使用此项目。
如果服务模块希望获取用户名,则不应使用此功能,而应执行对 pam_get_user(3)的调用。
仅服务模块有权读取身份验证令牌 PAM_AUTHTOK 和 PAM_OLDAUTHTOK。
2.1.4.2. 返回值
-
PAM_BAD_ITEM
- 应用程序试图设置一个未定义或不可访问的项目。
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_PERM_DENIED
-
- item *的值为 NULL。
-
-
PAM_SUCCESS
- 数据更新成功。
-
PAM_SYSTEM_ERR
- 作为第一个参数传递的* pam_handle_t *无效。
2.1.5. 获取用户名
#include <security/pam_modules.h>
int pam_get_user(
pamh,
user,
prompt);
const pam_handle_t *pamh;
const char **user;
const char *prompt;
2.1.5.1. DESCRIPTION
pam_get_user
函数返回由 pam_start(3)指定的用户名。如果未指定用户,则返回pam_get_item (pamh, PAM_USER, ... );
返回的内容。如果为 NULL,则通过 pam_conv(3)机制获取用户名,并使用以下列表中的第一个非 NULL 字符串提示用户:
-
- prompt *参数传递给函数。
-
pam_get_item(pamh,PAM_USER_PROMPT,...)返回的内容;
-
默认提示:“登录名:”
无论通过哪种方式获得用户名,都将返回指向它的指针作为** user 的内容。请注意,此内存不应由模块“释放”()或“修改” *。
此函数设置与 pam_set_item(3)和 pam_get_item(3)函数关联的* PAM_USER *项目。
2.1.5.2. 返回值
-
PAM_SUCCESS
- 用户名已成功检索。
-
PAM_SYSTEM_ERR
- 提交了空指针。
-
PAM_CONV_ERR
- 应用程序提供的对话方法无法获取用户名。
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_ABORT
- 恢复旧的对话时出错。
-
PAM_CONV_AGAIN
- 应用程序提供的对话方法正在 await 事件。
2.1.6. 对话功能
#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;
};
2.1.6.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])
2.1.6.2. 返回值
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_CONV_ERR
- 通话失败。该应用程序不应设置** resp *。
-
PAM_SUCCESS
- Success.
2.1.7. 设置或更改 PAM 环境变量
#include <security/pam_appl.h>
int pam_putenv(
pamh,
name_value);
pam_handle_t *pamh;
const char *name_value;
2.1.7.1. DESCRIPTION
pam_putenv
函数用于添加或更改与* pamh *句柄关联的 PAM 环境变量的值。
- pamh *参数是通过先前调用 pam_start()获得的身份验证句柄。 * name_value *参数是单个 NUL 终止的字符串,具有以下形式之一:
-
NAME =变量值
- 在这种情况下,给定 NAME 的环境变量将设置为指示的值:* variable 的值*。如果该变量是已知的,它将被覆盖。否则,它将被添加到 PAM 环境中。
-
NAME=
- 此函数将变量设置为空值。单独列出以表明这是实现此设置的正确方法。
-
NAME
- 如果没有'=',则
pam_putenv
()函数将从 PAM 环境中删除相应的变量。
- 如果没有'=',则
pam_putenv
()对* name_value *的副本进行操作,这意味着与 putenv(3)相比,应用程序负责释放数据。
2.1.7.2. 返回值
-
PAM_PERM_DENIED
- 给定参数* name_value *是一个 NULL 指针。
-
PAM_BAD_ITEM
- 当前未设置请求的变量(用于删除)。
-
PAM_ABORT
-
- pamh *句柄已损坏。
-
-
PAM_BUF_ERR
- 内存缓冲区错误。
-
PAM_SUCCESS
- 环境变量已成功更新。
2.1.8. 获取一个 PAM 环境变量
#include <security/pam_appl.h>
const char *pam_getenv(
pamh,
name);
pam_handle_t *pamh;
const char *name;
2.1.8.1. DESCRIPTION
pam_getenv
函数在与句柄* pamh 关联的 PAM 环境列表中搜索与 name *所指向的字符串匹配的项,并返回指向环境变量值的指针。该应用程序不允许释放数据。
2.1.8.2. 返回值
pam_getenv
函数在失败时返回 NULL。
2.1.9. 获取 PAM 环境
#include <security/pam_appl.h>
char **pam_getenvlist(
pamh);
pam_handle_t *pamh;
2.1.9.1. DESCRIPTION
pam_getenvlist
函数返回与句柄* pamh *关联的 PAM 环境的完整副本。 PAM 环境变量表示授予服务时已认证用户的常规环境变量的内容。
内存的格式是 malloc()的 char 指针数组,其最后一个元素设置为 NULL。该数组中的每个非 NULL 条目都指向一个 NUL 终止且 malloc()的 char 字符串,其形式为“ * name = value *”。
应该注意的是,此内存永远不会由 libpam 释放。一旦通过调用pam_getenvlist
获得,调用应用程序有责任释放()该内存。
返回的数组的格式和内容是设计使然,而不是巧合,与 execle(3)函数调用的第三个参数所需的格式和内容相匹配。
2.1.9.2. 返回值
pam_getenvlist
函数在失败时返回 NULL。