c++ - 创建不带 PIPE_REJECT_REMOTE_CLIENTS 的NamedPipe

标签 c++ c winapi named-pipes

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

您可以在 Vista 及更高版本中传递该函数,以阻止远程连接 (PIPE_REJECT_REMOTE_CLIENTS)。据我了解,这意味着管道只能在同一台机器上连接。有谁知道如何在早期版本的 Windows 中获得相同的功能?我尝试使用以下代码创建一个 SECURITY_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;
}

如果有人可以告诉我我做的事情是否正确,或者我可以在哪里寻找 SECURITY_ATTRIBUTES 的明确解释,我将不胜感激。

最佳答案

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

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

if(!::SetEntriesInAcl (1, &ea, NULL, &acl)) 

SetEntriesInAcl 返回 DWORD 代码,而不是 BOOL:成功时返回的代码为 ERROR_SUCCESS,其值为 0L,因此您的函数始终在此时退出,使 SECURITY_ATTRIBUTES 结构留空。

您的代码还会泄漏内存,因为它无法释放某些 API(包括 SetEntriesInAcl)创建的缓冲区。我建议您使用the example in MSDN作为确保您进行所有必要清理的指南。

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

  • 使用单个 ACE,每个可以访问管道的人都拥有完全相同的访问权限:您已经失去了更紧密地控制管道安全性的能力。至少,您通常希望确保只有预期的管道服务器可以创建管道的新实例,并限制更改管道安全性的能力。
  • 授予本地组成员身份的访问 token 的确切情况没有很好的记录,我怀疑该组的组成员身份与您的要求不完全一致。 CreateNamedPipe 的文档明确指出,要在早期平台上获得与 PIPE_REJECT_REMOTE_CLIENTS 相同的结果,您应该拒绝对 NETWORK 的访问。

因此,您的代码需要修改,以便构建包含以下 ACE 的 DACL:

  1. 针对知名安全标识符组 NETWORK USERS 的“拒绝”ACE,拒绝所有访问
  2. “允许”ACE,允许作为管道服务器的应用程序创建管道实例
  3. “允许”ACE,允许作为管道客户端的应用程序读取和写入管道

其中第一个是阻止远程访问管道的原因,因为远程访问协议(protocol)(包括基于 SMB 的远程命名管道协议(protocol))创建的所有登录 token 都会自动包含 NETWORK USERS 组的组成员身份(以及-已知SID S-1-5-2)。此拒绝 ACE 必须位于 DACL 中的允许 ACE 之前。

您没有说明哪个应用程序是管道服务器,哪个是客户端。如果两者都在交互式用户 session 中运行,也许这并不重要:在这种情况下,您可以仅使用一个允许 ACE,它授予用户 session 对 SID 的所有访问权限。

如果没有有关您的安全要求的更多详细信息,就很难规范您应如何设置服务器和客户端 ACE。然而,几乎可以肯定,您会想要限制 FILE_CREATE_PIPE_INSTANCE 的访问权限,以便只有管道服务器拥有它。

关于c++ - 创建不带 PIPE_REJECT_REMOTE_CLIENTS 的NamedPipe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11004775/

相关文章:

c - 在c中传递引用?

创建自定义队列

windows - 将 SetupDiSetDeviceRegistryProperty 与 SPDRP_HARDWAREID 结合使用

c++ - 是否可以在 win32 应用程序中嵌入命令提示符?

c - 是否有一个简单的库(适用于多个平台)可以轻松地将数组数据写入文件?

c++ - 如何将程序的句柄赋予它创建的进程?

c++ - C++ 中的溢出数字 (Visual Studio 2013)

c++ - 注册表问题 - 使用 C++ 删除键/值

c++ - 颜色类型 3 的 PNG 图像纹理格式

c++ - 基于范围的循环不适用于数组指针