8#include <QtCore/private/qsystemerror_p.h>
25using namespace Qt::StringLiterals;
27bool QLocalServerPrivate::addListener()
31 listeners.push_back(std::make_unique<Listener>());
32 auto &listener = listeners.back();
34 SECURITY_ATTRIBUTES sa;
35 sa.nLength =
sizeof(SECURITY_ATTRIBUTES);
36 sa.bInheritHandle = FALSE;
37 sa.lpSecurityDescriptor = 0;
39 std::unique_ptr<SECURITY_DESCRIPTOR> pSD;
42 QByteArray tokenUserBuffer;
43 QByteArray tokenGroupBuffer;
46 if ((socketOptions.value() & QLocalServer::WorldAccessOption)) {
47 pSD.reset(
new SECURITY_DESCRIPTOR);
48 if (!InitializeSecurityDescriptor(pSD.get(), SECURITY_DESCRIPTOR_REVISION)) {
49 setError(
"QLocalServerPrivate::addListener"_L1);
53 if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
55 DWORD dwBufferSize = 0;
56 GetTokenInformation(hToken, TokenUser, 0, 0, &dwBufferSize);
57 tokenUserBuffer.fill(0, dwBufferSize);
58 auto pTokenUser =
reinterpret_cast<PTOKEN_USER>(tokenUserBuffer.data());
59 if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
60 setError(
"QLocalServerPrivate::addListener"_L1);
66 GetTokenInformation(hToken, TokenPrimaryGroup, 0, 0, &dwBufferSize);
67 tokenGroupBuffer.fill(0, dwBufferSize);
68 auto pTokenGroup =
reinterpret_cast<PTOKEN_PRIMARY_GROUP>(tokenGroupBuffer.data());
69 if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
70 setError(
"QLocalServerPrivate::addListener"_L1);
76#ifdef QLOCALSERVER_DEBUG
79 SID_NAME_USE groupNameUse;
81 LookupAccountSid(0, pTokenGroup->PrimaryGroup, 0, &groupNameSize, 0, &domainNameSize, &groupNameUse);
82 auto groupName = std::unique_ptr<
wchar_t[]>(
new wchar_t[groupNameSize]);
83 auto domainName = std::unique_ptr<
wchar_t[]>(
new wchar_t[domainNameSize]);
84 const bool lookup = LookupAccountSid(0, pTokenGroup->PrimaryGroup, groupName.get(),
85 &groupNameSize, domainName.get(), &domainNameSize,
88 qDebug() <<
"primary group" << QString::fromWCharArray(domainName.get()) <<
"\\"
89 << QString::fromWCharArray(groupName.get()) <<
"type=" << groupNameUse;
91 if (ConvertSidToStringSid(pTokenGroup->PrimaryGroup, &groupNameSid)) {
92 qDebug() <<
"primary group SID" << QString::fromWCharArray(groupNameSid) <<
"valid" << IsValidSid(pTokenGroup->PrimaryGroup);
93 LocalFree(groupNameSid);
97 SID_IDENTIFIER_AUTHORITY WorldAuth = { SECURITY_WORLD_SID_AUTHORITY };
98 if (!AllocateAndInitializeSid(&WorldAuth, 1, SECURITY_WORLD_RID,
101 setError(
"QLocalServerPrivate::addListener"_L1);
106 DWORD aclSize =
sizeof(ACL) + ((
sizeof(ACCESS_ALLOWED_ACE)) * 3);
107 aclSize += GetLengthSid(pTokenUser->User.Sid) -
sizeof(DWORD);
108 aclSize += GetLengthSid(pTokenGroup->PrimaryGroup) -
sizeof(DWORD);
109 aclSize += GetLengthSid(worldSID) -
sizeof(DWORD);
110 aclSize = (aclSize + (
sizeof(DWORD) - 1)) & 0xfffffffc;
112 aclBuffer.fill(0, aclSize);
113 auto acl =
reinterpret_cast<PACL>(aclBuffer.data());
114 InitializeAcl(acl, aclSize, ACL_REVISION_DS);
116 if (socketOptions.value() & QLocalServer::UserAccessOption) {
117 if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenUser->User.Sid)) {
118 setError(
"QLocalServerPrivate::addListener"_L1);
123 if (socketOptions.value() & QLocalServer::GroupAccessOption) {
124 if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenGroup->PrimaryGroup)) {
125 setError(
"QLocalServerPrivate::addListener"_L1);
130 if (socketOptions.value() & QLocalServer::OtherAccessOption) {
131 if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, worldSID)) {
132 setError(
"QLocalServerPrivate::addListener"_L1);
137 SetSecurityDescriptorOwner(pSD.get(), pTokenUser->User.Sid, FALSE);
138 SetSecurityDescriptorGroup(pSD.get(), pTokenGroup->PrimaryGroup, FALSE);
139 if (!SetSecurityDescriptorDacl(pSD.get(), TRUE, acl, FALSE)) {
140 setError(
"QLocalServerPrivate::addListener"_L1);
145 sa.lpSecurityDescriptor = pSD.get();
148 listener->handle = CreateNamedPipe(
149 reinterpret_cast<
const wchar_t *>(fullServerName.utf16()),
150 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
154 PIPE_REJECT_REMOTE_CLIENTS,
155 PIPE_UNLIMITED_INSTANCES,
161 if (listener->handle == INVALID_HANDLE_VALUE) {
162 setError(
"QLocalServerPrivate::addListener"_L1);
163 listeners.pop_back();
170 memset(&listener->overlapped, 0,
sizeof(OVERLAPPED));
171 listener->overlapped.hEvent = eventHandle;
175 if (!ConnectNamedPipe(listener->handle, &listener->overlapped)) {
176 switch (GetLastError()) {
177 case ERROR_IO_PENDING:
178 listener->connected =
false;
180 case ERROR_PIPE_CONNECTED:
181 listener->connected =
true;
184 CloseHandle(listener->handle);
185 setError(
"QLocalServerPrivate::addListener"_L1);
186 listeners.pop_back();
190 Q_ASSERT_X(
false,
"QLocalServerPrivate::addListener",
"The impossible happened");
191 SetEvent(eventHandle);
196void QLocalServerPrivate::setError(
const QString &function)
198 int windowsError = GetLastError();
199 errorString = QString::fromLatin1(
"%1: %2").arg(function, qt_error_string(windowsError));
200 error = QAbstractSocket::UnknownSocketError;
203void QLocalServerPrivate::init()
207bool QLocalServerPrivate::removeServer(
const QString &name)
213bool QLocalServerPrivate::listen(
const QString &name)
217 const auto pipePath =
"\\\\.\\pipe\\"_L1;
218 if (name.startsWith(pipePath))
219 fullServerName = name;
221 fullServerName = pipePath + name;
226 eventHandle = CreateEvent(NULL, TRUE, FALSE, NULL);
227 connectionEventNotifier =
new QWinEventNotifier(eventHandle , q);
228 q->connect(connectionEventNotifier, SIGNAL(activated(HANDLE)), q, SLOT(_q_onNewConnection()));
230 for (
int i = 0; i < listenBacklog; ++i)
234 _q_onNewConnection();
238bool QLocalServerPrivate::listen(qintptr)
240 qWarning(
"QLocalServer::listen(qintptr) is not supported on Windows QTBUG-24230");
244void QLocalServerPrivate::_q_onNewConnection()
254 ResetEvent(eventHandle);
258 for (size_t i = 0; i < listeners.size(); ) {
259 HANDLE handle = listeners[i]->handle;
260 if (listeners[i]->connected
261 || GetOverlappedResult(handle, &listeners[i]->overlapped, &dummy, FALSE))
263 listeners.erase(listeners.begin() + i);
267 if (pendingConnections.size() > maxPendingConnections)
268 connectionEventNotifier->setEnabled(
false);
273 q->incomingConnection(
reinterpret_cast<quintptr>(handle));
275 if (GetLastError() != ERROR_IO_INCOMPLETE) {
277 setError(
"QLocalServerPrivate::_q_onNewConnection"_L1);
287void QLocalServerPrivate::closeServer()
289 connectionEventNotifier->setEnabled(
false);
290 connectionEventNotifier->deleteLater();
291 connectionEventNotifier = 0;
292 CloseHandle(eventHandle);
293 eventHandle =
nullptr;
294 for (size_t i = 0; i < listeners.size(); ++i)
295 CloseHandle(listeners[i]->handle);
299void QLocalServerPrivate::waitForNewConnection(
int msecs,
bool *timedOut)
302 if (!pendingConnections.isEmpty() || !q->isListening())
305 DWORD result = WaitForSingleObject(eventHandle, (msecs == -1) ? INFINITE : msecs);
306 if (result == WAIT_TIMEOUT) {
310 _q_onNewConnection();
Combined button and popup list for selecting options.