现在的位置: 首页 > 综合 > 正文

NT Service中OpenFileMapping”拒绝访问”错误之分析

2013年11月04日 ⁄ 综合 ⁄ 共 1770字 ⁄ 字号 评论关闭

最近在写一个双接口的组件,当中用到了内存映射文件的共享:通过启动一个程序
CreateFileMapping创建内存映射,然后在组件OpenFileMapping进行读取.在对双接口的调试中,一切都还顺利:直接在程序中
CoCreateInstanse,或者在windows脚本中CreateObject,组件都很正常的工作.但是当我在一个ASP页面中调用该组件
后,却发现组件出错了.
跟踪程序后发现,组件在OpenFileMapping后返回NULL值,GetLastError返回5,该错误
为"ERROR_ACCESS_DEINED"即"拒绝访问".奇怪的是,在程序和脚本中OpenFileMapping都没有出错,那么ASP执行与脚
本或程序执行的差别是在哪里呢?
在NT系统中运行的IIS,对ASP的解释执行是由World Wide Web
Publishing这个服务来完成的,那么ASP脚本中的CreateObject,以及后续的对组件的操作,实际上是由Web服务程序来调用的,因此
ASP执行与脚本(由WScript.exe解释)或程序执行的区别就是:在ASP中,前者的OpenFileMapping是NTService调用
的,而后者是普通的Win32程序调用的.
在NTService中的OpenFileMapping返回"拒绝访问"错误,正是因为CreateFileMapping创建的内存文件对象,在
NTService中对其没有访问权限.我们在使用CreateFileMapping函数时,通常忽略掉了一个参
数"LPSECURITY_ATTRIBUTES
lpFileMappingAttributes",我们一般将其置为NULL.MSDN对该参数的描述是,当该值为NULL时,该对象具有默认的访问权
限.而默认的访问权限就是,同一账户启动的所有程序都可以访问该对象,这些程序一般包括我们自己写的Win32程序,windows脚本解释器.
于是我做了一个测试,另外建了一个Administraotrs组的账户,然后用原账户启动服务程序CreateFileMapping,再把我之前运行正常的测试客户程序以新建账户的身份运行,不出所料,我的测试客户程序也出错了,与ASP页面的错误原因是一模一样的.
大部分系统服务(NTService)并不是以当前登录用户的身份启动运行的,它们一般是运行在LocalSystem这个账户
下.LocalSystem这个账户比较有意思,在"计算机管理"中我们看不到这个用户,但它却实实在在存在,只是它只能被本地计算机识别,而无法远程登
录.Web服务也是由LocalSystem启动的,自然它也无法访问由Administrator用户创建的内存映射文件对象.

错误原因分析完了,解决方法自然也就出来了.只要在CreateFileMapping的时候指定一个访问权限即可,这个权限可以允许任何人访问该对象,代码如下:
PSECURITY_DESCRIPTOR pSec = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(!pSec)
{
return GetLastError();
}
if(!InitializeSecurityDescriptor(pSec, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree(pSec);
return GetLastError();
}
if(!SetSecurityDescriptorDacl(pSec, TRUE, NULL, TRUE))
{
LocalFree(pSec);
return GetLastError();
}
SECURITY_ATTRIBUTES attr;
attr.bInheritHandle = FALSE;
attr.lpSecurityDescriptor = pSec;
attr.nLength = sizeof(SECURITY_ATTRIBUTES);
HANDLE hFile = CreateFileMapping(INVALID_HANDLE_VALUE, &attr, PAGE_READWRITE, 0, 1024, "test");
LocalFree(pSec);

抱歉!评论已关闭.