//转载请注明来源:http://blog.csdn.net/tingya
//版权声明:
//本书是《Apache源代码全景分析》的草稿部分,
//读者可以自由浏览和打印
//未经本文允许,不得以任何形式出现在盈利印刷品中,否则将追究法律责任!!!
6.1.2.2Window平台
相比于Unix下的apr_procattr_t结构,Window下的该结构定义要简单一些,它定义在Unix下的进程属性结构定义在srclib\apr\include\arch\win32\apr_arch_threadproc.h中,如下:
struct apr_procattr_t {
apr_pool_t *pool;
/*Part 1*/
apr_file_t *parent_in;
apr_file_t *child_in;
apr_file_t *parent_out;
apr_file_t *child_out;
apr_file_t *parent_err;
apr_file_t *child_err;
/*Part 2*/
char *currdir;
apr_int32_t cmdtype;
apr_int32_t detached;
apr_child_errfn_t *errfn;
apr_int32_t errchk;
/*Part 3*/
HANDLE user_token;
LPSECURITY_ATTRIBUTES sa;
LPVOID sd;
};
Window中该结构包含三方面的内容:
■ 第一部分
该部分与Unix中的功能相同,描述了父进程和子进程之间通信的三个管道文件:一个管道用于从父进程写入数据,从子进程中读出;一个管道用于从子进程写入数据,从父进程中读出;一个管道负责子进程写入错误信息通知父进程。与Unix类似,Window中的管道创建可以使用apr_procattr_io_set统一创建,也可以使用apr_procattr_child_in_set单独创建。apr_procattr_io_set函数实现如下:
APR_DECLARE(apr_status_t) apr_procattr_io_set(apr_procattr_t *attr,
apr_int32_t in,
apr_int32_t out,
apr_int32_t err)
{
apr_status_t stat = APR_SUCCESS;
if (in) {
if (in == APR_CHILD_BLOCK)
in = APR_READ_BLOCK;
else if (in == APR_PARENT_BLOCK) u
in = APR_WRITE_BLOCK;
stat = apr_create_nt_pipe(&attr->child_in, &attr->parent_in, in,
attr->pool);
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_in);
}
if (out && stat == APR_SUCCESS) {
stat = apr_create_nt_pipe(&attr->parent_out, &attr->child_out, out,
attr->pool); v
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_out);
}
if (err && stat == APR_SUCCESS) {
stat = apr_create_nt_pipe(&attr->parent_err, &attr->child_err, err,
attr->pool); w
if (stat == APR_SUCCESS)
stat = apr_file_inherit_unset(attr->parent_err);
}
return stat;
}
在Window下,管道的创建通过内部函数apr_create_nt_pipe实现,具体的创建细节我们在第七章的”管道章节”会详细描述。不过在Window管道中,
■ 第二部分
■ 第三部分
第三部分的内容是Window所独有的,主要用于Window的安全性。为了了解这几个成员的真实含义,我们必须对Window 的安全性有一定的了解。
首先我们来看use_token,它是一个HANDLE类型,表示用户的访问令牌。与Window9X系列操作系统相比,Window NT以上的版本的安全性都得到了极大的提高。在Windows中,安全性是指将对象所受的保护与用户的访问权进行比较。如果用户拥有足够的访问权(访问权等于或超过对象所受的保护),则用户能够使用这个对象。在Windows 的文档中将对象所受保护的级别称作安全描述符(securitydescriptor),这是一种结构,它能告诉安全系统:用户需要什么样的权力才能访问这个对象;而用户则有一个访问令牌(Access),它是另一种结构,它能告诉安全系统:在一个给定的位置,用户有什么样的访问权。令牌包括多方面的内容:用户安全标示符(SID)、组SID列表、特权列表和模拟(Impersonating)信息,可以用下图描述: Token
用户将访问令牌交给Windows NT系统,并以此获得对对象的访问。当用户登录系统时,Windows NT/2000 将验证他的密码,如果用户验证成功,系统产生一个访问令牌。该用户启动的任何进程都将附加该令牌,访问令牌代表进程的安全环境,它控制了进程与可保护对象(securable object)的交互。当进程访问一个可保护对象时,系统将该对象的访问控制列表(ACL)中的每个访问控制项(ACE)和访问令牌中的 SID 进行比较以确定进程是否可以访问该对象。由于用户启动的任何进程都将附加该用户的访问令牌,因此任何进程都知道用户的 SID 并且可以访问它。
Window中不同的用户登录所产生的访问令牌是不一样的,因此它们的访问权限也不一样。在Window中大部分服务进程都是以本地系统帐户(local system)运行的,这是一个特殊的帐户,所以以本地系统帐户运行的进程和普通进程不同之处在于:
1) 注册表的 HKEY_CURRENT_USER 键是和缺省用户而不是当前用户相联系的,要访问其他用户的配置文件,需要先模拟该用户,然后再访问 HKEY_CURRENT_USER 。
2) 可以打开 HKEY_LOCAL_MACHINE\SECURITY 注册表键
3) 该进程不能访问网络资源,如共享、管道,因为它不能提供信任凭证,而只能使用空连接。 在 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters 处的 NullSessionPipes 和 NullSessionShares 的值指明了可以被空连接访问的管道和共享。
或者也可以设置 RestrictNullSessAccess = 0,以允许空连接的用户访问该计算机上的所有管道和共享。(呵呵,这个是个安全隐患哦,可不要干呀。上边两个值最好也全都设成空)
4) 不能和其他程序共享对象,除非在创建对象时设置 DACL 允许用户访问。
5) 如果启动命令行提示符来运行批处理文件,用户可以按 Ctrl+C 来终止批处理的运行,并且用户就获得了一个 Local System 权限的 shell。
正是由于服务程序运行在权限极大的 Local System 账号下,如果网络客户也使用该账号来访问系统将给系统带来安全隐患,因此 NT/2000 提供了模拟功能 --- 服务程序在处理客户请求时使用一个权限较低的客户身份运行,处理完客户请求再恢复。user_token则用于指定模拟的用户。不过Window中并不是直接使用字符串类型来描述账户。由于每一个账户都对应一个访问令牌,因此,window总是使用访问令牌标记模拟的用户。不过APR中提供了从用户名到访问令牌的转换函数apr_procattr_user_set。apr_proc_attr_user_set的实现细节我们在下一章描述。
如果user_token指定,那么在创建进程的时候,APR将使用该模拟用户创建进程。创建的过程我们在进程创建章节描述。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish1234 at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!