C++ CreateNamedPipe不带管道\u拒绝\u远程\u客户端

C++ CreateNamedPipe不带管道\u拒绝\u远程\u客户端,c++,c,winapi,named-pipes,C++,C,Winapi,Named Pipes,我正在尝试使用windows APICreateNamedPipe创建一个双工命名管道,用于shell扩展和主桌面应用程序之间的IPC 您可以为Vista及以上版本传递一个标志,该标志用于防止远程连接(PIPE\u REJECT\u remote\u CLIENTS)。据我所知,这意味着管道只能在同一台机器上连接。有人知道如何在早期版本的Windows中获得相同的功能吗?我尝试用以下代码创建一个SECURITY\u ATTRIBUTES对象,但我不完全确定它是否正常工作: static bool

我正在尝试使用windows API
CreateNamedPipe
创建一个双工命名管道,用于shell扩展和主桌面应用程序之间的IPC

您可以为Vista及以上版本传递一个标志,该标志用于防止远程连接(
PIPE\u REJECT\u remote\u CLIENTS
)。据我所知,这意味着管道只能在同一台机器上连接。有人知道如何在早期版本的Windows中获得相同的功能吗?我尝试用以下代码创建一个
SECURITY\u ATTRIBUTES
对象,但我不完全确定它是否正常工作:

static bool GetLocalMachineOnlySecurityAttributes (SECURITY_ATTRIBUTES& sa)
{
    PSID plocalsid = NULL;
    SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
    if(!::AllocateAndInitializeSid (&SIDAuthWorld, 1, SECURITY_LOCAL_RID, 0, 0, 0, 0, 0, 0, 0, &plocalsid))
        return false;

    EXPLICIT_ACCESS ea = {0};
    ea.grfAccessPermissions = SPECIFIC_RIGHTS_ALL | STANDARD_RIGHTS_ALL;
    ea.grfAccessMode = SET_ACCESS;
    ea.grfInheritance = NO_INHERITANCE;
    ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea.Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea.Trustee.ptstrName  = reinterpret_cast<LPWSTR>(plocalsid);

    PACL acl = NULL;
    if(!::SetEntriesInAcl (1, &ea, NULL, &acl))
        return false;

    //PSECURITY_DESCRIPTOR sd = reinterpret_cast<PSECURITY_DESCRIPTOR>(::LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH));
    static SECURITY_DESCRIPTOR sd = {0};
    if(!::InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION))
        return false;
    if(!::SetSecurityDescriptorDacl(&sd, TRUE, acl, FALSE))
        return false;

    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = &sd;
    sa.bInheritHandle = FALSE;
    return true;
}
static bool GetLocalMachineOnlySecurityAttributes(安全属性&sa)
{
PSID plocalsid=NULL;
SID\u标识符\u权限SIDAuthWorld=安全性\u本地\u SID\u权限;
if(!::AllocateAndInitializeSid(&SIDAuthWorld,1,SECURITY\u LOCAL\u RID,0,0,0,0,0,0,&plocalsid))
返回false;
显式访问ea={0};
ea.grfAccessPermissions=特定的_权限|所有|标准的_权限|;
ea.grfAccessMode=设置访问权限;
ea.grfInheritance=无继承;
ea.Trustee.TrusteeForm=受托人\u是\u SID;
ea.Trustee.TrusteeType=受托人是众所周知的集团;
ea.Trustee.ptstrName=重新解释(plocalsid);
PACL-acl=NULL;
if(!::setEntriesAcl(1,&ea,NULL,&acl))
返回false;
//PSECURITY_DESCRIPTOR sd=重新解释强制转换(::LocalAlloc(LPTR,SECURITY_DESCRIPTOR_MIN_LENGTH));
静态安全描述符sd={0};
if(!::初始化安全描述符(&sd,安全描述符\修订版))
返回false;
if(!::setSecurityDescriptorACL(&sd,TRUE,acl,FALSE))
返回false;
sa.nLength=sizeof(安全属性);
sa.lpSecurityDescriptor=&sd;
sa.bInheritHandle=FALSE;
返回true;
}

如果有人能告诉我我是否做了正确的事情,或者我可以在某个地方找到关于
安全属性的明确解释,我将不胜感激。

您确实可以通过为管道创建适当的自主访问控制列表(DACL)来阻止远程连接

您的代码正在尝试但未能做到这一点,第一个原因如下:

if(!::SetEntriesInAcl (1, &ea, NULL, &acl)) 
setEntriesAcl返回一个DWORD代码,而不是BOOL:成功时返回的代码是
ERROR\u success
,它的值为0L,因此您的函数总是在此时退出,而安全属性结构为空

您的代码也会泄漏内存,因为它无法释放某些API创建的缓冲区,包括
setEntriesAcl
。我建议你作为一个指导,以确保你做所有必要的清理

更多地关注代码的策略,您目前正在尝试使用允许本地安全组的所有访问的单个访问控制条目(ACE)来解决问题。因为DACL的工作方式,这不是正确的方法。。。相反,您应该拒绝远程访问(即黑名单),而不是尝试白名单本地访问。这至少有两个原因:

  • 使用一个ACE,每个可以访问管道的人都拥有完全相同的访问权限:您已经失去了更紧密地控制管道安全性的能力。至少,您通常希望确保只有预期的管道服务器可以创建管道的新实例,并限制更改管道安全性的能力
  • 访问令牌被授予本地组成员资格的确切情况没有很好的文档记录,我怀疑该组的组成员资格与您的要求不完全一致。CreateNamedPipe的文档明确指出,要获得与早期平台上的PIPE\u REJECT\u REMOTE\u客户端相同的结果,您应该拒绝访问网络
因此,需要修改代码,以便构建包含以下ACE的DACL:

  • 一个“拒绝”ACE,用于著名的安全标识符组网络用户,拒绝所有访问
  • “允许”ACE,允许作为管道服务器的应用程序创建管道实例
  • “允许”ACE,允许作为管道客户端的应用程序读取和写入管道
  • 第一个是阻止远程访问管道的原因,因为由远程访问协议(包括基于SMB的远程命名管道协议)创建的所有登录令牌自动包含网络用户组的组成员身份(众所周知的SID S-1-5-2)。此拒绝ACE必须位于DACL中的允许ACE之前

    您不会说哪个应用程序是管道服务器,哪个是客户端。如果两者都在交互用户的会话中运行,那么这可能无关紧要:在这种情况下,您可能只能够使用一个允许ACE,它为用户的会话授予对SID的所有访问权


    如果没有更多关于安全性要求的详细信息,就很难规定如何设置服务器和客户端ACE。但是,几乎可以肯定的是,您希望限制文件\u CREATE\u PIPE\u实例的访问权限,以便只有PIPE服务器拥有它。

    非常感谢您的回复!这是很多信息。我已经按照您的建议修复了泄漏,并修复了从SetEntriesAcl返回的处理。为了向您提供更多信息,我的桌面应用程序(只是一个简单的gui应用程序)创建了管道。explorer扩展是连接到管道的客户端。我认为填充SECURITY_ATTRIBUTES结构的最大困难是文档,尽管文档非常庞大,但对新手来说却很吓人。关于如何创建这些ACE,您有什么建议吗?可能是安全描述符字符串格式?另外,请看一眼,您能告诉我是否为各种结构使用了正确的标志和继承值吗?web上的许多示例在创建它们的API时混合并匹配来自不同API的标志