UWP C# 管道客户端无法连接到 Win32 C++ 管道服务器

Posted

技术标签:

【中文标题】UWP C# 管道客户端无法连接到 Win32 C++ 管道服务器【英文标题】:UWP C# pipe client fails to connect to Win32 C++ pipe server 【发布时间】:2021-01-05 11:17:02 【问题描述】:

我正在尝试在客户端 UWP C# 应用程序和服务器 Win32 C++ 应用程序之间进行通信,这两个应用程序都在同一个包中,并且我使用 Win32 应用程序作为桌面扩展来为 UWP 应用程序提供额外的功能。

从docs 可以清楚地看出,同一包中的 UWP 应用程序之间的命名管道通信,但不清楚同一包中的 UWP 和 Win32 应用程序。

UWP 进程创建的名为\\\\.\\pipe\\Local\\PipeName 的管道被转换为\\\\.\\pipe\\Sessions\\<SessionId>\\AppContainerNamedObjects\\<AppContainerSid>\\PipeName。我可以使用它在作为服务器的 UWP 和作为客户端的 Win32 之间进行通信。但即使在我设置了official RPC sample 中的 ACL 之后,我也无法执行相反的操作。我没有使用自定义功能,而是使用 DeriveAppContainerSidFromAppContainerName 从包系列名称派生 SID。

我的 Win32 C++ 服务器代码如下所示:

SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
PSID everyoneSid = NULL;
PSID packageSid = NULL;
EXPLICIT_ACCESS ea[2] = ;
PACL acl = NULL;
SECURITY_DESCRIPTOR pipeSecurityDescriptor = ;

if (DeriveAppContainerSidFromAppContainerName(Package::Current().Id().FamilyName().c_str(), &packageSid) == S_OK &&
    // Get the SID that represents 'everyone' (this doesn't include AppContainers)
    AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &everyoneSid))

    // Now create the Access Control List (ACL) for the Security descriptor

    // Everyone GENERIC_ALL access
    ea[0].grfAccessMode = SET_ACCESS;
    ea[0].grfAccessPermissions = GENERIC_ALL;
    ea[0].grfInheritance = NO_INHERITANCE;
    ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP;
    ea[0].Trustee.ptstrName = static_cast<LPWSTR>(everyoneSid);

    // Package Family GENERIC_ALL access
    ea[1].grfAccessMode = SET_ACCESS;
    ea[1].grfAccessPermissions = GENERIC_ALL;
    ea[1].grfInheritance = NO_INHERITANCE;
    ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
    ea[1].Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
    ea[1].Trustee.ptstrName = static_cast<LPWSTR>(packageSid);

    if (SetEntriesInAcl(ARRAYSIZE(ea), ea, NULL, &acl) != ERROR_SUCCESS &&
        // Initialize an empty security descriptor
        InitializeSecurityDescriptor(&pipeSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION) &&
        // Assign the ACL to the security descriptor
        SetSecurityDescriptorDacl(&pipeSecurityDescriptor, TRUE, acl, FALSE))
    
        SECURITY_ATTRIBUTES pipeSecurityAttributes .nLength = sizeof(SECURITY_ATTRIBUTES), .lpSecurityDescriptor = &pipeSecurityDescriptor, .bInheritHandle = FALSE ;
        HANDLE hPipe = CreateNamedPipe(L"\\\\.\\pipe\\Sessions\\<SessionId>\\AppContainerNamedObjects\\<AppContainerSid>\\PipeName", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, NMPWAIT_WAIT_FOREVER, &pipeSecurityAttributes);
        if (hPipe)
        
           ConnectNamedPipe(hPipe, NULL);
           // Do something
        
    


if (everyoneSid) FreeSid(everyoneSid);
if (packageSid) FreeSid(packageSid);
if (acl) LocalFree(acl);

我的 UWP C# 客户端代码如下所示:

using (var client = new NamedPipeClientStream(".", "Local\\PipeName", PipeDirection.InOut, PipeOptions.Asynchronous))
        
            await client.ConnectAsync();
            // Do something
        

当我尝试从客户端连接时,我收到 "Access to the path is denied." 错误。

【问题讨论】:

虽然这个问题看起来和***.com/questions/60431348/…很像,但这个问题的答案并不令人满意,关于这个问题的讨论早已平息。 这里有什么不满意的地方? @RbMm 答案提供了对所有包的访问权限,但我只需要访问同一包中的 UWP 进程。 但是这里有什么问题?设置安全描述符以仅允许访问此包,而不是“D:P(A;;GA;;;WD)(A;;GA;;;AC)(A;;GA;;;S-1-15-2 -2)S:(ML;;;;;LW)”。并且此 SD 不仅必须在管道上,而且还必须用于通过 RpcServerRegisterIf3 设置的 rpc。您还可以设置自定义安全回调检查 (RPC_IF_CALLBACK_FN) 以过滤您的流程 IIRC 命名管道在 C# 中被破坏,因为它们使用了特定的 Win32 API。尝试直接 P/Invoke 到 CreateFile 然后我认为您可以将 HANDLE (IntPtr) 转换为 .NET 流? 【参考方案1】:

我能够得到这个工作的一个版本——一个 C# UWP 应用管道客户端成功连接到一个非 UWP C++ 管道服务器。我的设置与您的非常相似,但有一些不同。

    我在使用 C# 版本连接客户端时一点运气都没有。我成功使用了CreateFileW。您可以使用 DllImport 在 C# 内部调用此函数。 我的管道名称略有不同。我的非 UWP 程序是我的管道服务器,所以我认为我不需要使用“本地”子路径。我的服务器管道路径是:\\\\.\\pipe\\Pipe。我的客户端管道路径是:\\.\pipe\\Pipe。我能够与这些名字建立联系。 根据我自己使用DeriveAppContainerSidFromAppContainerName 的经验,我似乎无法从中获得正确的SID。我会得到一个,但是当我将它与 Powershell 中“CheckNetIsolation.exe LoopbackExempt -s”的 SID 进行比较时,它就不同了。不知道为什么会这样,但我硬编码了正确的 SID 并且有效。 SID 不正确会导致访问被拒绝错误。

【讨论】:

"Local" 显然是为了处理终端服务中的多登录会话支持(即使在 Windows 的客户端版本上作为“快速用户切换”功能的一部分也是活动的)。但是,这不适用于命名管道:***.com/a/3214370/103167 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。

以上是关于UWP C# 管道客户端无法连接到 Win32 C++ 管道服务器的主要内容,如果未能解决你的问题,请参考以下文章

如何将命名管道c#服务器连接到命名管道php客户端

是否可以从 C# 应用程序连接到 32 位 C++ RPC 服务器应用程序

命名管道客户端无法连接到作为网络服务运行的服务器

C# 客户端通过 SSL 连接到 Java 服务器

c#命名管道双向通信

从 Windows 上的 C# Service Fabric 应用程序连接到 docker_engine(命名管道)