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 的安全性有一定的了解。
用户将访问令牌交给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将使用该模拟用户创建进程。创建的过程我们在进程创建章节描述。