跨域访问命名管道
文档版本
版本
创建时间
创建人
备注
1.0.0604.1
2003-6-4
郑 昀
第一稿
Implementation Scope:
本文档将说明如何跨越两个互相不信任的Windows 2000 域使用命名管道。问题最终解决,我有幸记录下了排查、解决问题的全过程。
继续阅读之前,我们假设您熟悉以下知识:
n Named Pipe
n Access Control List
n Discretionary Access Control List
n IIS 5.0
现象
同事遇到了这么一个问题:
“我做了一个com(dll),这个com将被asp调用,连接到一个namedpipe。现在遇到了一些访问权限问题:
COM和namedpipe位于同一个计算机
使用vbs测试,com可访问管道
使用iis,则com不能访问管道,错误代码是:5,Access is denied.
COM和namedpipe位于不同的域中的计算机,IIS与COM位于同一个计算机
使用vbs测试,com不能访问管道,错误代码:1326,Logon failure: unknown user name or bad password
使用iis,不能访问..错误代码是:5,Access is denied.
COM和namedpipe位于不同的域中的计算机
但在COM所在计算机上使用 net use \\server2\pipe /USER:xxx
指定了用户名,密码之后
使用vbs测试,com可访问管道
使用iis,不能访问..错误代码是:5,Access is denied.
综合起来,问题在于IIS进程调用的COM,访问另外的程序创建的命名管道时候,因权限问题而无法访问。”
解决步骤需要做两步:
u 管道服务器端 在创建命名管道的时候,要明确指定DACL为NULL。如果不指定这一步,客户端将返回错误码:5(拒绝访问)。事实上只有管道创建者才可以访问管道。
u 客户端 客户端连接之前,使用WNetAddConnection2 进行网络连接登录。实际测试中发现,如果不进行这一步,运行结果返回错误码:1326。
DACL的指定
Pipes的安全是由ACL控制的。
同时我们需要了解IIS的进程身份。如果IIS虚拟目录指定的“应用程序保护”是”中”,那么IIS的ASP执行线程运行在IUSER_MachineName身份下。参见如下表格:
序号
应用
程序
保护
匿名账号
Thread TokenProcess Token
1
低(IIS进程)
admin
TOMOSOFT\admin
Token Type:
Impersonation
Impersonation Level:
Delegation
NT AUTHORITY\SYSTEM
Token Type:
Primary
Impersonation Level:
Anonymous
2
中
IUSR_SERVER
SERVER\IUSR_SERVER
Token Type:
Impersonation
Impersonation Level:
Impersonation
TOMOSOFT\admin
Token Type:
Primary
Impersonation Level:
Delegation
3
低(IIS进程)
IUSR_SERVER
UMSERVER\IUSR_UMSERVER
Token Type:
Impersonation
Impersonation Level:
Impersonation
NT AUTHORITY\SYSTEM
Token Type:
Primary
Impersonation Level:
Anonymous
详细情况请参见我的另一篇文档:
http://www.csdn.net/Develop/read_article.asp?id=14257
《IIS 5.0的运行身份》
当你创建了一个命名管道,它的安全参数指定了NULL,这就表明只有创建者才可以作为Client访问这个命名管道。
所以,ASP执行线程是无权访问命名管道的。
那么在我们遇到的这种情况下,希望指定命名管道为所有人所能访问,那就可以通过创建一个空的DACL来做到。
你很容易就想到要用以下两个函数:
InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)和
SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)。
提请注意:第二个参数bDaclPresent参一定要是TRUE,这样才表明第三个参数pDacl有意义。这样我们才明确指定了一个NULL DACL作为安全描述符。
创建这样一个Everyone可以访问的命名管道,代码如下(已经删除了错误处理代码):
SECURITY_ATTRIBUTES sa;
PSECURITY_DESCRIPTOR pSD;
// create a security NULL security
// descriptor, one that allows anyone
// to write to the pipe... WARNING
// entering NULL as the last attribute
// of the CreateNamedPipe() will
// indicate that you wish all
// clients connecting to it to have
// all of the same security attributes
// as the user that started the
// pipe server.
pSD = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR,
SECURITY_DESCRIPTOR_MIN_LENGTH);
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION))
{
LocalFree((HLOCAL)pSD);
return;
}
// add a NULL disc. ACL to the
// security descriptor.
if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE))
{
LocalFree((HLOCAL)pSD);
return;
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = pSD;
sa.bInheritHandle = TRUE;
// Create a local named pipe with
// the name '\\.\PIPE\demo'. The
// '.' signifies local pipe.
hPipe = CreateNamedPipe ("\\\\.\\PIPE\\demo", // Pipe name = 'demo'.
PIPE_ACCESS_DUPLEX // 2 way pipe.
| FILE_FLAG_OVERLAPPED, // Use overlapped structure.
PIPE_WAIT // Wait on messages.
| PIPE_READMODE_MESSAGE // Specify message mode pipe.
| PIPE_TYPE_MESSAGE,
MAX_PIPE_INSTANCES, // Maximum instance limit.
OUT_BUF_SIZE, // Buffer sizes.
IN_BUF_SIZE,
TIME_OUT, // Specify time out.
&sa); // Security attributes.
// Check Errors.
if ((DWORD)(DWORD_PTR)hPipe == 0xFFFFFFFF)
{
printf("hPipe == 0xFFFFFFFF !!!!!!!!!!!!");
};
网络连接显式登录在指定了命名管道可为Everyone访问之后,我们的试验依旧一再遭遇错误码“1326”。
后来发现,客户端连接命名管道时出错,其实和命名管道无关,即使试图打开一个不存在的NamedPipe,依然遭遇错误“1326”。所以我们认为还是需要网络连接显式登录。
所以,用到了以下代码:
NETRESOURCE ns;
ns.dwScope =RESOURCE_CONNECTED;
ns.dwType =RESOURCETYPE_ANY;
ns.dwDisplayType =RESOURCEDISPLAYTYPE_GENERIC;
ns.dwUsage =RESOURCEUSAGE_CONNECTABLE;
ns.lpRemoteName=(char*)PipeName;//服务器端的管道名
ns.lpLocalName =NULL;
ns.lpProvider =NULL;
DWORD dwErr;
dwErr=WNetAddConnection2(&ns, "password", "username", 0);
这样,就可以了。
更多信息
没有指定NULL DACL之前,我们很容易利用指定IIS的虚拟目录的匿名身份做到让IIS访问命名管道的。就是,设置 虚拟目录à属性à目录安全性à“匿名访问和身份验证控制”编辑à匿名访问使用账户 为一个创建命名管道的那个账户。当然,这样做很不安全,但是有效。
我们没有采用这个做法。
解决了NULL DACL问题之后,我们甚至按照以下这篇文章的指示,修改了服务器端的本地安全策略:
《Q126645 Access Denied When Opening a Named Pipe from a Service》
这上面说,一个SYSTEM账户身份运行的服务打开一个命名管道遇到访问禁止的错误,那么请修改注册表:
\HKEY_LOCAL_MACHINE\
SYSTEM\
CurrentControlSet\
Services\
LanmanServer\
Parameters\
NullSessionPipes
把你的命名管道名字加入,然后重启计算机。
我们试过了,没有作用。
看来我们的问题不在于NULL Session。
其实,修改注册标的这个动作,你完全可以在 本地安全策略à本地策略à安全选项à网络访问:可匿名访问的命名管道 中找到。效果是一样的。
总结:
跨域(两个互相不信任的Windows2000域)访问命名管道的解决之道:
1:
管道服务器端,在创建命名管道的时候,要指定DACL为NULL;这个很必要;
2:
客户端端连接之前,一定要进行模拟网络连接登录。
要不然,什么1326、1398、53、998等等错误码你都可以见到。
Disclaimers:
本文档所包含的信息代表了在发布之日,zhengyun对所讨论问题的当前看法。本文档不应理解为zhengyun一方的承诺,zhengyun不保证所给信息在发布之日以后的准确性。
本文档仅供参考。
用户必须遵守所有适用的版权法。在不对版权法所规定的权利加以限制的情况下,如未得到 zhengyun和CSDN.Net明确的书面许可,不得出于任何目的、以任何形式或手段(电子的、机械的、影印、录制等等)复制、传播本文的任何部分,也不得将其存储或引入到检索系统中。
Thank zy_zhang;
Written by zhengyun (at) tomosoft.com
本文地址:http://com.8s8s.com/it/it1728.htm