[Pipe]跨域访问命名管道

类别:VC语言 点击:0 评论:0 推荐:

跨域访问命名管道

 

文档版本

版本

创建时间

创建人

备注

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。现在遇到了一些访问权限问题:

COMnamedpipe位于同一个计算机

       使用vbs测试,com可访问管道

       使用iis,则com不能访问管道,错误代码是:5,Access is denied.      

 

COMnamedpipe位于不同的域中的计算机,IISCOM位于同一个计算机

       使用vbs测试,com不能访问管道,错误代码:1326,Logon failure: unknown user name or bad password   

       使用iis,不能访问..错误代码是:5,Access is denied.

 

COMnamedpipe位于不同的域中的计算机

       但在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 Token

Process 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不保证所给信息在发布之日以后的准确性。

本文档仅供参考。

用户必须遵守所有适用的版权法。在不对版权法所规定的权利加以限制的情况下,如未得到 zhengyunCSDN.Net明确的书面许可,不得出于任何目的、以任何形式或手段(电子的、机械的、影印、录制等等)复制、传播本文的任何部分,也不得将其存储或引入到检索系统中。

 

Thank zy_zhang;

Written by zhengyun (at) tomosoft.com

 

 

本文地址:http://com.8s8s.com/it/it1728.htm