免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3273 | 回复: 0
打印 上一主题 下一主题

Solaris操作系统的用户认证:第4部分:PAM 服务模块 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-01-20 10:56 |只看该作者 |倒序浏览

学习为验证和安全服务编写 PAM(可插拔验证模块)服务模块,并研究示例模块。
目录

简介
在本系列的前三篇文章(
第 1 部分

第 2 部分

第 3 部分
)中,我们介绍了基于密码的用户验证的基础知识,并重点讨论 PAM(可插拔验证模块)的作用。我们阐述为应用程序(称为 PAM 使用者)提供验证功能的 PAM API,并演示了如何编写 PAM 会话函数。
在第 4 部分(也是最后一篇)中,我们将介绍 PAM 服务模块并演示如何编写它们的示例程序。
服务模块

服务模块 是一个共享库,它提供了以下一项或多项验证和安全服务:

  • 验证:这些服务模块用于验证对帐户或服务的访问,并设置用户凭证。
  • 帐户管理:这些服务模块确定正在访问的帐户的有效性。例如,帐户管理模块可以检查密码或帐户过期时间,或强制设置访问时间或帐户锁定限制。
  • 会话管理:这些服务模块负责设置和去除以前验证的用户或服务的 PAM 会话。
  • 密码管理:这些服务模块强制执行密码强度和使用之前的规则,并执行验证标记更新。

理想情况下,PAM 服务应该在任务简单并且定义明确的服务模块中实现,因此增加配置的灵活性。然后即可根据 PAM 配置文件(/etc/pam.conf)中相应定义的要求使用服务模块。我们在本系列的
第 2 部分
中描述了 PAM 配置文件。
服务模块需求

在本系列的第 2 部分中我们提到 PAM 使用者调用以下一个或多个函数来执行用户验证和相关功能:

  • pam_authenticate
  • pam_acct_mgmt
  • pam_setcred
  • pam_open_session
  • pam_close_session
  • pam_chauthtok

以上每个函数都是由服务模块中拥有相同名称(但 pam_ 前缀替换成 pam_sm_)的函数实现的。因此 pam_authenticate 是由 pam_sm_authenticate 实现的,pam_sm_acct_mgmt 实现 pam_acct_mgmt,以次类推。我们编写的服务模块必须提供以上一个或多个函数。
为了与 PAM 使用者应用程序通信,服务模块使用 pam_get_item 和 pam_set_item 函数,如以下代码示例所示。还应指出 PAM 使用者可以使用这些函数与服务模块通信。
#include
int pam_get_item(const pam_handle_t *pamh, int item_type,
         void **item);
int pam_set_item(pam_handle_t *pamh, int item_type,
         const void *item);

pam_set_item 函数允许服务模块更新句柄 pamh 指定的 PAM 事务信息。item_type 指定的信息类型可以是 pam_set_item 手册页中指定的十二种项目类型之一。项目类型示例包括 PAM_AUTHTOK、PAM_CONV、PAM_USER 和 PAM_USER_PROMPT。想要将 PAM 信息设置成的值是由 item 指定的。
类似地,可以通过调用 pam_get_item 访问 PAM 事务的信息。在这种情况下,指定类型的 PAM 信息的指针被放到 item 中。
服务模块通过使用 pam_get_data 和 pam_set_data 函数,可以访问和更新特定于模块的信息。我们不深入讨论这些函数,因为我们重点研究 PAM 服务模块及其使用者之间的通信。有兴趣的读者可以参考这些函数的手册页,了解更多详细信息。
PAM 服务模块必须向其使用者提供 PAM 返回代码。返回代码必须为以下三种类型之一:

  • PAM_SUCCESS。 模块做出肯定性的决定,此决定是所请求的策略的一部分。
  • PAM_IGNORE。 模块没有做出属于所请求的策略一部分的决定。
  • PAM_error>。 模块做出否定性的决定,此决定是所请求的策略的一部分。错误代码可以是普通的 PAM 基础架构错误代码(例如,PAM_USER_UNKNOWN 是指示 PAM 句柄指定的用户未知的错误,PAM_PERM_DENIED 的意思是此模块拒绝了验证请求,等等),也可以是特定于模块的错误代码。在后一种情况下,错误代码必须是每个模块唯一的(也就是,不能被任何其他模块使用),因此应该记录在模块的手册页中。

要防止显式不需要的消息,所有服务模块都必须遵照 PAM_SILENT 标志的指示。推荐使用 debug 标志,以便通过 syslog 设施将诊断调试信息记入日志。使用 syslog 记录的调试消息应该使用 LOG_AUTH 设施和 LOG_DEBUG 严重性级别。使用 syslog 记录的任何其他消息都应该使用 LOG_AUTH 设施和相应的优先级。
重要注意事项: syslog 相关的函数 openlog、closelog 和 setlogmask 不能 在服务模块中使用,因为它们干扰应用程序的设置。
服务模块示例

既然描述了服务模块及其必须执行的工作,下面将查看一个模块。我们编写的服务模块提供了以下机制:特定组中的指定用户被拒绝访问。此服务模块适用的情况示例为 web hosting 公司:允许客户通过 ftp 和 sftp 连接,但禁止使用登录 shell。通过使用此模块并在禁止组中指出客户名称,可以强制执行此访问策略。
此帐户访问策略类型适用于成功验证的用户,因此其特色是帐户管理。PAM 感知的应用程序调用 pam_acct_mgmt 来执行此任务,因此示例模块实现了 pam_sm_acct_mgmt,其原型如下所示:
#include
#include
int pam_sm_acct_mgmt (pam_handle_t *pamh, int flags, int argc,
         const char **argv);

pamh 引用 pam_start 返回的 PAM 句柄,flags 包含应用程序传递到此模块的任何标志,argc 和 argv 包含 pam.conf 中指定的模块选项编号和相应的选项列表。
下面是示例模块的源码。
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
  
7 int pam_sm_acct_mgmt (pam_handle_t *ph, int flags, int argc, char **argv)
8 {
9     char *user = NULL;
10     char *host = NULL;
11     char *service = NULL;
12     char *denied_group = "";
13     char group_buf[8192];
14     struct group grp;
15     struct pam_conv *conversation;
16     struct pam_message msg;
17     struct pam_message *msgp = &msg;
18     struct pam_response *resp = NULL;
19     int i;
20     int err;
21     int no_warn = 0;
22     int debug = 0;
23     int ret_val;
   
24     for (i = 0; i conv (1, &msgp, &resp, conversation->appdata_ptr);
64                 if (debug && err != PAM_SUCCESS) {
65                     syslog (LOG_AUTH | LOG_DEBUG, "%s: denied_group: conversation returned %s",
66                       service, pam_strerror (ph, err));
67                 }
   
68                 if (resp != NULL) {
69                     if (resp->resp)
70                         free (resp->resp);
71                     free (resp);
72                 }
73             }
   
74             syslog (LOG_AUTH | LOG_NOTICE, "%s: denied_group: Connection for %s "
75               "not allowed from %s", service, user, host);
76             ret_val = PAM_PERM_DENIED;
77             goto out;
78         }
79     }
   
80     if (debug)
81         syslog (LOG_AUTH | LOG_DEBUG, "%s: denied_group: user %s is not a member of "
82           "group %s.  Access granted.", service, user, grp.gr_name);
83     
84     ret_val = PAM_SUCCESS;
   
85 out:
86     return (ret_val);
87 }

仔细研究下这个 80 行的函数。注意,为了便于讨论本示例,我们随意将缓冲区 group_buf(在第 13 行定义)限制为 8K 字符。在实际的程序中,可能根据系统的最大值动态地设置此缓冲区的大小,通过调用 sysconf 确定。
1-6:包含必要的头文件。
24-33:解释模块选项,设置合适的调试和非警告标志。
34-36:获得用户、服务和远程主机名称。
37-41:如果用户未指定,则拒绝访问。
44-49:如果指定的组未定义,则拒绝访问。
50-56:如果指定的组没有指定成员,则允许所有用户访问。
57-79:检查用户是不是组的成员。如果是,则拒绝访问,并且(如果没有禁用警告)调用会话函数向用户传递相应的错误消息。注意,总是向 syslog 报告此拒绝。注意,为了简便起见,我们使用 strcmp 来比较用户名。在实际的应用程序中,可能使用 strncmp,以避免缓冲区溢出。还要注意,第 66 行中 pam_strerror 的用法。此函数返回与第二个参数相关的错误消息,其处理方式与 strerror 处理常规错误消息相同。
80-84:如果执行到此处,则用户不是指定组的成员,因此允许访问。
85-87:返回调用程序。
服务模块是共享对象,因此可借助 Sun 的 Studio 编译器使用以下命令来构建示例。
rich@ultra20# cc -c -Kpic -o pam_service_module.so pam_service_module.c

(gcc 用户应该将 -Kpic 替换成 -fpic。)
PAM 基础架构执行各种安全检查,因此共享对象必须归 root 所有,如以下示例所示。
rich@ultra20# su -
root@ultra20# chown root:root /home/rich/pam_service_module.so

测试完服务模块并准备部署时,通常将共享对象置于 /usr/lib/security/$ISA 中,其中 $ISA 表示目标机器的指令集。另一个可能安装此模块的位置(如果以包的格式提供模块)是 /opt/lib/security/$ISA。
最后,必须向 pam.conf 添加新模块的一个条目,如下所示。
other   account  required   /home/rich/pam_service_module.so group=staff debug

一切正常的话,则组 staff 的指定成员将被拒绝访问。指定为 staff 组成员的 rich 用户尝试使用 ssh 登录时,就会失败,如以下示例所示。(使用 telnet 也会失败,但是有安全意识的人不应该使用 telnet。)
rich@sunblade1000# ssh ultra20
Connection closed by 192.168.0.2

修改拒绝用户组(比如说修改为 root)将允许 rich 用户登录,如下所示。
rich@sunblade1000# ssh ultra20
Last login: Sun Dec  2 16:43:05 2007 from sunblade1000
Sun Microsystems Inc.   SunOS 5.11      snv_70  October 2007
rich@ultra20#

将用户 rich 从名为 staff 的组成员列表中删除,会产生相同的效果。
结束语

在本文中,我们介绍了 PAM 服务模块的概念及其必须实现的功能(也就是我们对服务模块的期望)。首先讲到服务模块必须实现以下一个或多个函数,具体取决于服务模块的目的:pam_sm_authenticate、pam_sm_acct_mgmt、pam_sm_setcred、pam_sm_open_session、pam_sm_close_session 和 pam_sm_chauthtok。还简要描述了服务模块和 PAM 使用者与服务模块用来彼此通信的两个函数。
然后描述了服务模块必须返回给调用者的值类型,它指示请求成功、被忽略还是产生错误(包括失败)。
然后讨论了期望的服务模块日志记录类型,以及什么时候不记录特定消息,并展示了实现以下策略的示例服务模块:拒绝访问指定组中的指定成员。
最后,展示了如何构建和安装服务模块。


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/23363/showart_2154428.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP