没有PIPE_REJECT_REMOTE_CLIENTS的CreateNamedPipe

时间:2012-06-12 20:58:23

标签: 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的明确解释,我将非常感激。

1 个答案:

答案 0 :(得分:3)

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

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

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

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

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

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

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

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

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

    您没有说您的哪个应用程序是管道服务器以及哪个应用程序是客户端。也许无关紧要,如果两者都在交互式用户的会话中运行:在这种情况下,您可能只能使用一个允许ACE,该ACE允许对用户会话的所有SID访问权限。

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