Qt 4.8.1的Windows 7实现Microsoft中出现以下问题:
QLocalServer(命名管道)正在等待客户端连接,并且它作为以管理权限(例如系统服务)运行的服务器应用程序运行。
如何允许非特权 QLocalSocket 客户端连接到该服务器?连接尝试总是被拒绝,错误代码为 3 (QLocalSocket::SocketAccessError)。有解决办法吗?
编辑:正如我发现的那样,解决方案是通过允许完全访问"每个人"Sid来更改管道安全性。这里唯一的问题是,对SetSecurityInfo
的调用总是失败并显示"拒绝访问"错误。首先,我们必须获得一个管道手柄。由于管道已经由Qt创建,我们将用CreateNamedPipe
打开它。
HANDLE hPipe = CreateNamedPipe(
(const wchar_t *)_Server->fullServerName().utf16(), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
PIPE_TYPE_BYTE | // byte type pipe
PIPE_READMODE_BYTE | // byte-read mode
PIPE_WAIT, // blocking mode
PIPE_UNLIMITED_INSTANCES, // max. instances
0, // output buffer size
0, // input buffer size
3000, // client time-out
0 // Default Security
);
// Same call to open/create pipe as in qlocalserver_win.cpp
// Code here to add/change ACEs
if (SetSecurityInfo(hPipe, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
0, 0, NewAcl, 0) == ERROR_SUCCESS) {
// Success
}
即使NewAcl
设置为 NULL,调用也会失败。那么什么可能导致"访问被拒绝"错误呢?
,现在有点晚了,但这可能有助于其他有相同问题的人。请注意,仅当服务器是您的应用程序时,此解决方案才有效。
如果是这种情况,只需在调用 listen
之前调用 server.setSocketOptions(QLocalServer::WorldAccessOption);
或 QLocalServer::SocketOption
的其他值之一。
熟悉Qt,所以不知道当你以这种方式使用QtLocalServer时,默认情况下会创建哪些安全特征。但是,通常有两种不同的机制可能导致"拒绝访问"错误。
第一个是与管道关联的 DACL(自由访问控制列表)。其工作方式与 Windows 中任何安全对象上的 DACL 相同(例如文件安全性)。列表中必须有一个访问控制项 (ACE),该条目授予客户端用户所需的管道访问权限类型。正如正确指示的那样,为允许读/写访问的"所有人"SID 添加 ACE 将消除客户端面临的任何 DACL 障碍。但是,请注意,修改 DACL 的代码必须已经具有对管道的WRITE_DAC访问权限,否则它将无法打开可通过其修改 DACL 的句柄。您的代码在调用 CreateNamedPipe 时甚至不会请求WRITE_DAC访问权限,因此这是对 SetSecurityInfo 的调用失败的另一个原因。
第二种机制是 Windows Vista 及更高版本中引入的强制完整性控制机制。从您的描述中不清楚这是否在这里发挥作用,但通常,客户端进程永远无法对安全资源具有写入访问权限,该安全资源的完整性级别低于资源的完整性级别。如果这是这里的问题(并且由于您的标题专门涉及Windows 7,我想可能是),唯一的解决方案是更改管道上的强制完整性标签,以将管道的完整性级别降低到客户端的完整性级别。为此,您需要访问服务器打开的第一个管道句柄(此问答解释了原因),因为完整性标签是管道的系统访问控制列表(SACL)中包含的特殊ACE,您需要WRITE_OWNER预先进行更改。在Qt中掌握这个管道手柄是否可行是我不知道的。
我找到了Qt问题的解决方案。由于在调用 QLocalServer::listen() 后不能使用 CreateNamedPipe
创建的句柄,我们可以在 Qt 之前调用CreateNamedPipe
。如果我们用WRITE_DAC | FILE_FLAG_FIRST_PIPE_INSTANCE
来调用它,我们可以改变任何东西。
然后我们可以按照克里斯·迪克森的说法更改安全设置。