接前一篇文章:PAM从入门到精通(十四)
本文参考:
《The Linux-PAM Application Developers' Guide》
先再来重温一下PAM系统架构:
更加形象的形式:
六、整体流程示例
1. 官方文档中的例程及解析
从PAM从入门到精通(四)起到上一回止,整体结合实例讲解了《The Linux-PAM Application Developers' Guide》中的“Chapter 3. The public interface to Linux-PAM”中的3.1,实际上对应了上图中的PAM-API部分。不过看了各函数之后,对于总体流程还是缺少了了解和把握。本回就以一个示例(代码)将之前这些函数串起来,以对于总体流程以及各函数之间的顺序和关系有更好的理解。
示例代码参见《The Linux-PAM Application Developers' Guide》的“Chapter 8. An example application ”。
为了了解Linux PAM应用程序的编写方式,我们包括以下示例。它会提示用户输入密码,并在标准输出中指示他们的帐户是否有效,其返回代码也指示成功与否(0表示成功;1表示失败)。
代码如下:
/*
This program was contributed by Shane Watts
[modifications by AGM and kukuk]
You need to add the following (or equivalent) to the
/etc/pam.d/check_user file:
# check authorization
auth required pam_unix.so
account required pam_unix.so
*/
#include <security/pam_appl.h>
#include <security/pam_misc.h>
#include <stdio.h>
static struct pam_conv conv = {
misc_conv,
NULL
}
int main(int argc, char *argv[])
{
pam_handle_t *pamh=NULL;
int retval;
const char *user="nobody";
if(argc == 2) {
user = argv[1];
}
if(argc > 2) {
fprintf(stderr, "Usage: check_user [username]\n");
exit(1);
}
retval = pam_start("check_user", user, &conv, &pamh);
if (retval == PAM_SUCCESS)
retval = pam_authenticate(pamh, 0); /* is user really user? */
if (retval == PAM_SUCCESS)
retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
/* This is where we have been authorized or not. */
if (retval == PAM_SUCCESS) {
fprintf(stdout, "Authenticated\n");
} else {
fprintf(stdout, "Not Authenticated\n");
}
if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
pamh = NULL;
fprintf(stderr, "check_user: failed to release authenticator\n");
exit(1);
}
return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */
}
说实话,这代码写得很一般,argc为1时的情况没有考虑进来。不过不必关注这些细枝末节,人家把主要的流程讲清楚了。整个流程分为以下步骤:
(1)pam_start函数
代码片段:
retval = pam_start("check_user", user, &conv, &pamh);
作用:
PAM事务初始化。
pam_start函数创建PAM上下文并启动PAM事务。它是应用程序需要调用的第一个PAM函数。事务状态完全包含在此句柄标识的结构中,因此可以并行处理多个事务。但是不可能对不同的事务使用相同的句柄,每个新的上下文都需要一个新的句柄。
(2)pam_authenticate函数
代码片段:
retval = pam_authenticate(pamh, 0); /* is user really user? */
作用:
对用户进行身份认证。
pam_authenticate函数用于对用户进行身份验证。用户被要求提供一个基于身份验证服务的身份验证令牌,通常这是一个密码,但也可能是指纹。
PAM服务模块可以请求用户通过对话机制输入其用户名(参见pam_start()和pam_conv())。经过身份验证的用户名称将出现在PAM的PAM_USER项中。可以通过调用pam_get_item()来恢复此项目。
(3)pam_acct_mgmt函数
代码片段:
retval = pam_acct_mgmt(pamh, 0); /* permitted access? */
作用:
账户验证管理。
pam_acct_mgmt函数用于确定用户的帐户是否有效。它检查身份验证令牌和帐户过期与否,并验证访问限制。其通常在用户经过身份验证后调用。
(4)pam_end
代码片段:
if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */
pamh = NULL;
fprintf(stderr, "check_user: failed to release authenticator\n");
exit(1);
}
作用:
PAM事务终止。
pam_end函数终止pam事务,是应用程序应在pam上下文中调用的最后一个函数。此函数为与pam_set_item和pam_get_item函数关联的项释放了所有内存。调用pam_end()后,与此类对象关联的指针不再有效。