Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1275537
  • 博文数量: 554
  • 博客积分: 10425
  • 博客等级: 上将
  • 技术积分: 7555
  • 用 户 组: 普通用户
  • 注册时间: 2006-11-09 09:49
文章分类

全部博文(554)

文章存档

2012年(1)

2011年(1)

2009年(8)

2008年(544)

分类:

2008-04-14 09:56:26


第2 章• 开发特权应用程序23
一般情况下,应该将基本权限作为集来指定,而不是分别指定。此方法将确保指定中包
括Solaris OS 更新版本中发布的所有基本权限。另一方面,应该显式禁用程序不需要的
已知权限。例如,如果程序不适用于exec(1) 子进程,则应禁用proc_exec 权限。
 文件系统权限。
 System V 进程间通信(Interprocess Communication, IPC) 权限。
 网络权限。
 进程权限。
 系统权限。
有关Solaris 权限的完整列表以及说明,请参见privileges(5) 手册页。
注– Solaris 提供区域功能,通过此功能,管理员可以为运行的应用程序设置隔离环境。请参
见zones(5)。由于一个区域中的进程无法监视或干扰该区域外系统中的其他活动,因此该进
程的所有权限也限于该区域。但是,如果需要,可以将PRIV_PROC_ZONE 权限应用于全
局区域中需要权限才能在非全局区域中操作的进程。
使用权限进行编程
本节讨论使用权限的接口。要使用权限编程接口,需要以下头文件。
#include
本节还提供了说明如何在特权应用程序中使用权限接口的示例。
权限数据类型
以下是权限接口使用的主要数据类型:
 权限类型-单个权限由priv_t 类型定义表示。可以按照以下方式使用权限ID 字符串初
始化priv_t 类型的变量:
priv_t priv_id = PRIV_FILE_DAC_WRITE;
 权限集类型-权限集由priv_set_t 数据结构表示。请使用表2–1 中列出的某个权限处理
函数来初始化priv_set_t 类型的变量。
 权限操作类型-对文件或进程权限集执行的操作类型由priv_op_t 类型定义表示。并不
是所有的操作对每种类型的权限集都有效。有关详细信息,请阅读第24 页中的“使用
权限进行编程”中的权限集说明。
权限操作可以具有以下值:
 PRIV_ON -在指定的文件或进程权限集中启用在priv_set_t 结构中声明的权限。
 PRIV_OFF -在指定的文件或进程权限集中禁用在priv_set_t 结构中声明的权限。
使用权限进行编程
24 Solaris 开发者安全性指南• 2006 年11 月
 PRIV_SET -将指定文件或进程权限集中的权限设置为在priv_set_t 结构中声明的权
限。如果将该结构初始化为空,则PRIV_SET 会将权限集设置为none。
权限接口
下表列出了使用权限的接口。表后面提供了一些主要权限接口的说明。
表2–1使用权限的接口
目的函数其他注释
获取和设置权限集setppriv(2)、getppriv(2)、priv_sseett(3pCpr)i、v(p)riv_ineffect(3C) 和getppriv() 是系
统调用。priv_ineffect() 和
priv_set() 是为方便而使用的包
装函数。
识别和转换权限priv_str_to_set(3C)、priv_set_to_str(3C)、priv_getbyname(3C)、priv_getbynum(这些函数将指定的权限或权限集
映射到名称或编号。
处理权限集priv_allocset(3C)、priv_freeset(3C)、priv_emptyset(3C)、priv_fillset(3C)这些函数与权限内存分配测试
和各种设置操作有关。
获取和设置进程标志getpflags(2)、setpflags (2) PRIV_AWARE 进程标志指示进
程是否了解权限或是否在超级用
户模型下运行。PRIV_DEBUG
用于权限调试。
低级凭证处理ucred_get(3C) 这些例程用于调试、底层系统调
用和内核调用。
setppriv():用于设置权限
用于设置权限的主要函数为setppriv(),该函数具有以下语法:
int setppriv(priv_op_t op, priv_ptype_t which, \
const priv_set_t *set);
op 表示要执行的权限操作。op 参数具有以下三个可能值之一:
 PRIV_ON-将set 变量指定的权限添加到which 指定的权限集类型中
 PRIV_OFF-从which 指定的权限集类型中删除set 变量指定的权限
 PRIV_SET-使用set 变量指定的权限替换which 指定的权限集类型中的权限
which 用于指定要更改的权限集类型:
 PRIV_PERMITTED
 PRIV_EFFECTIVE
 PRIV_INHERITABLE
 PRIV_LIMIT
使用权限进行编程
第2 章• 开发特权应用程序25
set 指定要在更改操作中使用的权限。
此外,还提供了便利函数:priv_set()。
用于映射权限的priv_str_to_set()
这些函数便于使用其数值映射权限名称。priv_str_to_set() 是此系列中的典型函数。
priv_str_to_set() 具有以下语法:
priv_set_t *priv_str_to_set(const char *buf, const char *set, \
const char **endptr);
priv_str_to_set() 采用buf 中指定的权限名字符串。priv_str_to_set() 返回可以与四个权
限集之一组合的一组权限值。**endptr 可用于调试解析错误。请注意,可以在buf 中包括
以下关键字:
 “all” 指示所有已定义的权限。使用“all,!priv_name,...” 可以指定除指示权限以外的
所有权限。
注– 使用“priv_set, !priv_name,...” 的构造将从指定的权限集中删除指定的权限。如果事
先没有指定集,请不要使用“!priv_name,...”,因为如果没有从中删除权限的权限集,
该构造将从空的权限集中删除指定的权限,并有效指示无权限。
 “none” 指示无权限。
 “basic” 表示执行登录标准UNIX 操作系统的所有用户一般都可以执行的操作所需的权
限集。
权限编码示例
本节对使用超级用户模型和最低权限模型包括权限的方式进行比较。
包括在超级用户模型中的权限
以下示例说明如何在超级用户模型中包括特权操作。
示例2–1超级用户权限包括示例
/* Program start */
uid = getuid();
seteuid(uid);
使用权限进行编程
26 Solaris 开发者安全性指南• 2006 年11 月
示例2–1 超级用户权限包括示例(续)
/* Privilege bracketing */
seteuid(0);
/* Code requiring superuser capability */
...
/* End of code requiring superuser capability */
seteuid(uid);
...
/* Give up superuser ability permanently */
setreuid(uid,uid);
包括在最低权限模型中的权限
此示例说明如何在最低权限模型中包括特权操作。此示例使用以下假定:
 该程序为setuid 0。
 由于setuid 0,允许集和有效集最初设置为所有权限。
 可继承集最初设置为基本权限。
 限制集最初设置为所有权限。
代码后面是该示例的说明。
注– 此示例的源代码也可以通过Sun 下载中心获得。请访问

示例2–2最低权限包括示例
1 #include
2 /* Always use the basic set. The Basic set might grow in future
3 * releases and potentially retrict actions that are currently
4 * unrestricted */
5 priv_set_t *temp = priv_str_to_set("basic", ",", NULL);
使用权限进行编程
第2 章• 开发特权应用程序27
示例2–2 最低权限包括示例(续)
6 /* PRIV_FILE_DAC_READ is needed in this example */
7 (void) priv_addset(temp, PRIV_FILE_DAC_READ);
8 /* PRIV_PROC_EXEC is no longer needed after program starts */
9 (void) priv_delset(temp, PRIV_PROC_EXEC);
10 /* Compute the set of privileges that are never needed */
11 priv_inverse(temp);
12 /* Remove the set of unneeded privs from Permitted (and by
13 * implication from Effective) */
14 (void) setppriv(PRIV_OFF, PRIV_PERMITTED, temp);
15 /* Remove unneeded priv set from Limit to be safe */
16 (void) setppriv(PRIV_OFF, PRIV_LIMIT, temp);
17 /* Done with temp */
18 priv_freeset(temp);
19 /* Now get rid of the euid that brought us extra privs */
20 (void) seteuid(getuid());
21 /* Toggle PRIV_FILE_DAC_READ off while it is unneeded */
使用权限进行编程
28 Solaris 开发者安全性指南• 2006 年11 月
示例2–2 最低权限包括示例(续)
22 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL);
23 /* Toggle PRIV_FILE_DAC_READ on when special privilege is needed*/
24 priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL);
25 fd = open("/some/retricted/file", O_RDONLY);
26 /* Toggle PRIV_FILE_DAC_READ off after it has been used */
27 priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, NULL);
28 /* Remove PRIV_FILE_DAC_READ when it is no longer needed */
29 priv_set(PRIV_OFF, PRIV_ALLSETS, PRIV_FILE_DAC_READ, NULL);
该程序定义了名为temp 的变量。temp 变量确定此程序不需要的权限集。最初在第5 行,将
temp 定义为包含基本权限集。在第7 行,将file_dac_read 权限添加到temp 中。proc_exec
权限对exec(1) 新进程(在此程序中不允许)是必需的。因此,在第9 行中从temp 中删除了
proc_exec,从而使exec(1) 命令无法执行新进程。
此时,temp 仅包含该程序所需的那些权限,即基本集加上file_dac_read,再删除
proc_exec。在第11 行中,priv_inverse() 函数将计算temp 的逆向值,并将temp 的值重置
为补值。逆向值是从所有可能权限集中删除指定集(在本例中为temp)所得的结果。作为
第11 行的结果,temp 现在包含该程序永不使用的那些权限。在第14 行中,从允许集中删除
了temp 定义的不需要的权限。此删除操作还从有效集中有效地删除了这些权限。在第16 行
中,从限制集中删除了不需要的权限。在第18 行中,因为不再需要temp,因而释放了temp
变量。
该程序可以识别权限。因此,该程序不使用setuid,但可以将有效的UID 重置为第20 行中
的用户的实际UID。
在第22 行中,通过从有效集中删除file_dac_read 权限禁用了该权限。在实际的程序中,
需要file_dac_read 之前,还将发生其他活动。在该样例程序中,读取第25 行中的文件需
要file_dac_read。因此,在第24 行中,启用了file_dac_read。读取文件后,将再次从有
效集中立即删除file_dac_read。读取所有文件后,通过在所有权限集中禁用
file_dac_read,可永久地删除file_dac_read。
使用权限进行编程
第2 章• 开发特权应用程序29
下表说明了随着程序的运行如何转换权限集。已指出了行号。
表2–2权限集转换
步骤temp 集允许权限集有效权限集限制权限集
最初— 所有所有所有
第5 行-将temp 设置为基本权限基本所有所有所有
第7 行-将file_dac_read 添加到
temp 中。
基本+
file_dac_read
所有所有所有
第9 行-从temp 中删除了
proc_exec。
基本+
file_dac_read -
proc_exec
所有所有所有
第11 行-将temp 重置为逆向值。所有-(基本+
file_dac_read -
proc_exec)
所有所有所有
第14 行-在允许集中禁用不需要的
权限。
所有-(基本+
file_dac_read -
proc_exec)
基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
所有
第16 行-在限制集中禁用不需要的
权限。
所有-(基本+
file_dac_read -
proc_exec)
基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
第18 行-释放了temp 文件。— 基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
第22 行-禁用file_dac_read 直到需
要时再启用。
— 基本- proc_exec 基本- proc_exec 基本+
file_dac_read -
proc_exec
第24 行-需要时启用
file_dac_read。
— 基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
基本+
file_dac_read -
proc_exec
第27 行-执行read() 操作后禁用
file_dac_read。
— 基本- proc_exec 基本- proc_exec 基本+
file_dac_read -
proc_exec
第29 行-不再需要file_dac_read
时,从所有集中删除该权限。
— 基本- proc_exec 基本- proc_exec 基本- proc_exec
使用权限进行编程
30 Solaris 开发者安全性指南• 2006 年11 月
特权应用程序开发指南
本节为开发特权应用程序提供了以下建议:
 使用隔离系统。绝不应在生产系统中调试特权应用程序,因为不完整的特权应用程序可
能会危及安全。
 正确设置ID。调用进程的有效集中需要具备proc_setid 权限,以更改其用户ID、组ID
或补充组ID。
 使用权限包括。应用程序使用权限时,将覆盖系统安全策略。应该包括特权任务并仔细
进行控制,以确保不会破坏敏感信息。有关如何包括权限的信息,请参见第26 页中的
“权限编码示例”。
 使用基本权限启动。基本权限是最低操作所必需的。特权应用程序应该使用基本集启
动。然后,该应用程序应该适当地删除和添加权限。以下是典型的启动方案。
1. 守护进程以超级用户身份启动。
2. 守护进程启用基本权限集。
3. 守护进程禁用不必要的所有基本权限,例如PRIV_FILE_LINK_ANY。
4. 守护进程添加需要的所有其他权限,例如PRIV_FILE_DAC_READ。
5. 守护进程切换到守护进程UID。
 请避免shell 转义序列。shell 转义序列中的新进程可以使用父进程的可继承集中的任何权
限。因此,最终用户可以通过shell 转义序列违反信任。例如,某些邮件应用程序可能会
将!command 行解释为命令并执行该行。因而,最终用户可以创建脚本,以充分利用所有
邮件应用程序权限。建议删除不必要的shell 转义序列。
关于授权
授权存储在/etc/security/auth_attr 文件中。要创建使用授权的应用程序,请执行以下步
骤:
1. 扫描/etc/security/auth_attr 以查找一个或多个应用程序授权。
2. 请在程序开始时使用chkauthattr(3SECDB) 函数检查所需的授权。chkauthattr() 函数将
在以下位置按顺序搜索授权:
 policy.conf(4) 数据库中的AUTHS_GRANTED 键-AUTHS_GRANTED 指示缺省情
况下指定的授权。
 policy.conf(4) 数据库中的PROFS_GRANTED 键-PROFS_GRANTED 指示缺省情况
下指定的权限配置文件。chkauthattr() 将针对指定授权检查这些权限配置文件。
 user_attr(4) 数据库-此数据库存储为用户指定的安全属性。
 prof_attr(4) 数据库-此数据库存储为用户指定的权限配置文件。
如果chkauthattr() 在上述任何位置中都找不到权限授权,则将拒绝用户访问该程序。
3. 使管理员了解此应用程序需要哪些授权。您可以通过手册页或其他文档通知管理员。
关于授权
第2 章• 开发特权应用程序31
示例2–3检查授权
以下代码段说明如何使用chkauthattr() 函数检查用户的授权。在本例中,该程序将检查
solaris.job.admin 授权。如果用户具有此授权,则该用户可以读取或写入其他用户的文
件。如果没有此授权,则用户只能对其拥有的文件执行操作。
/* Define override privileges */
priv_set_t *override_privs = priv_allocset();
/* Clear privilege set before adding privileges. */
priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ,
priv_FILE_DAC_WRITE, NULL);
priv_addset(override_privs, PRIV_FILE_DAC_READ);
priv_addset(override_privs, PRIV_FILE_DAC_WRITE);
if (!chkauthattr("solaris.jobs.admin", username)) {
/* turn off privileges */
setppriv(PRIV_OFF, PRIV_EFFECTIVE, override_privs);
}
/* Authorized users continue to run with privileges */
/* Other users can read or write to their own files only */
关于授权
32 Solaris 开发者安全性指南• 2006 年11 月
编写PAM应用程序和服务
可插拔验证模块(Pluggable authentication module, PAM) 为系统登录应用程序提供了验证和相
关的安全服务。本章适用于希望通过PAM模块提供验证、帐户管理、会话管理和口令管理
的系统登录应用程序开发者。此外,还为PAM服务模块的设计者提供了相关的信息。本章
将讨论以下主题:
 第33 页中的“PAM框架介绍”
 第36 页中的“PAM配置”
 第41 页中的“编写使用PAM服务的应用程序”
 第57 页中的“编写提供PAM服务的模块”
PAM最初是由Sun 开发的。自此以后PAM规范提交给了X/Open,即现在的"Open
Group"。PAM规范可在《X/Open Single Sign-On Service (XSSO) - Pluggable Authentication》
(Open Group 在英国出版,ISBN:1-85912-144-6,1997 年6 月)中找
到。pam(3PAM)、libpam(3LIB) 和pam_sm(3PAM) 手册页中介绍了Solaris 实现的PAM。
PAM框架介绍
PAM框架由四个部分组成:
 PAM消费方
 PAM库
 pam.conf(4) 配置文件
 PAM服务模块,也称为提供者
该框架可为与验证相关的活动提供统一的执行方式。采用该方式,应用程序开发者可使用
PAM服务,而不必了解策略的语义。算法是集中提供的。可以独立于各个应用程序对算法
进行修改。借助PAM,管理员可以根据特定系统的需要调整验证过程,而不必更改任何应
用程序。调整是通过PAM配置文件pam.conf 来执行的。
下图说明了PAM体系结构。应用程序通过PAM应用编程接口(application programming
interface, API) 与PAM库进行通信。PAM模块通过PAM服务提供者接口(service provider
interface, SPI) 与PAM库进行通信。通过这种方式,PAM库可使应用程序和模块相互进行通
信。
3第3 章
33
图3–1 PAM体系结构
PAM服务模块
PAM服务模块是一个共享库,用于为系统登录应用程序(如login、rlogin 和telnet)提
供验证和其他安全服务。四种类型的PAM服务是:
 验证服务模块-用于授予用户访问帐户或服务的权限。提供此服务的模块可以验证用户
并设置用户凭证。
 帐户管理模块-用于确定当前用户的帐户是否有效。提供此服务的模块可以检查口令或
帐户的失效期以及限时访问。
 会话管理模块-用于设置和终止登录会话。
 口令管理模块-用于强制实施口令强度规则并执行验证令牌更新。
一个PAM模块可以实现其中的一项或多项服务。将简单模块用于明确定义的任务中可以增
加配置灵活性。因此,应该在不同的模块中实现PAM服务。然后,可以按照pam.conf(4)
文件中定义的方式根据需要使用这些服务。
例如,Solaris OS 为系统管理员提供了用于配置站点口令策略的pam_authtok_check(5) 模
块。pam_authtok_check(5) 模块可以检查符合各种强度条件的建议口令。
有关Solaris PAM模块的完整列表,请参见手册页第5 节:Standards, Environments, and
Macros。PAM模块的前缀为pam_。
PAM框架介绍
34 Solaris 开发者安全性指南• 2006 年11 月
PAM库
PAM库libpam(3LIB) 是PAM体系结构中的中心元素:
 libpam 可以导出API pam(3PAM)。应用程序可以调用此API 以执行验证、帐户管理、凭
证建立、会话管理以及口令更改。
 libpam 可以导入主配置文件pam.conf(4)。PAM配置文件可指定每种可用服务的PAM模
块要求。pam.conf 由系统管理员进行管理。
 libpam 可以导入SPI pam_sm(3PAM),而导出则由服务模块完成。
PAM验证过程
以消费方如何使用PAM库进行用户验证为例,请考虑login 如何验证用户:
1. login 应用程序通过调用pam_start(3PAM) 并指定login 服务来启动PAM会话。
2. 该应用程序将调用pam_authenticate(3PAM),后者是PAM库libpam(3LIB) 导出的PAM
API 的一部分。
3. 该库将在pam.conf 文件中搜索login 项。
4. 对于pam.conf 中为login 服务配置的每个模块,PAM库将调用
pam_sm_authenticate(3PAM)。pam_sm_authenticate() 函数是PAMSPI 的一部分。
pam.conf 控制标志和每个调用的结果将确定是否允许用户访问系统。第36 页中的
“PAM堆栈工作原理”对此过程进行了更详细的介绍。
通过此方式,PAM库可以将PAM应用程序与系统管理员已配置的PAM模块连接起来。
PAM消费方的要求
PAM消费方必须与PAM库libpam 链接。应用程序使用模块提供的任何服务之前,必须通
过调用pam_start (3PAM) 初始化其PAM 库的实例。调用pam_start() 可初始化必须传递给
所有后续PAM调用的句柄。应用程序完成使用PAM服务后,系统将调用pam_end() 以清除
PAM库已使用的任何数据。
PAM应用程序与PAM模块之间的通信是通过项进行的。例如,以下各项有助于进行初始化

 PAM_USER-当前验证的用户
 PAM_AUTHTOK-口令
 PAM_USER_NAME-用户名提示
 PAM_TTY-用户借此进行通信的终端
 PAM_RHOST-用户借此进入系统的远程主机
 PAM_REPOSITORY-对用户帐户系统信息库的任何限制
 PAM_RESOURCE-对资源的任何控制
 
 
以上文章转自于 : http://developers.sun.com.cn/
阅读(566) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~