summaryrefslogtreecommitdiffstats
path: root/src/network/socket/qlocalserver_win.cpp
diff options
context:
space:
mode:
authorShane Kearns <ext-shane.2.kearns@nokia.com>2012-05-02 15:32:09 +0100
committerQt by Nokia <qt-info@nokia.com>2012-05-03 16:11:58 +0200
commit39eb95ece12445af944cb9fd17136d7f6c20e4cd (patch)
tree5b40db41fae60c5d1607486ec6d7e649ed7c0445 /src/network/socket/qlocalserver_win.cpp
parent95c4be798c1d410c78580e952efc0168034fceaf (diff)
Implement QLocalServer::socketOptions on windows
Tested manually using the localfortuneserver example and multiple login sessions. The linux autotest isn't suitable for windows due to pipe permissions not appearing in the filesystem. Task-number: QTBUG-25147 Change-Id: I5ea4db81d1870dc45bd483fa8d0b06afede3b722 Reviewed-by: Joerg Bornemann <joerg.bornemann@nokia.com>
Diffstat (limited to 'src/network/socket/qlocalserver_win.cpp')
-rw-r--r--src/network/socket/qlocalserver_win.cpp120
1 files changed, 119 insertions, 1 deletions
diff --git a/src/network/socket/qlocalserver_win.cpp b/src/network/socket/qlocalserver_win.cpp
index 07357e5789..00eae32c99 100644
--- a/src/network/socket/qlocalserver_win.cpp
+++ b/src/network/socket/qlocalserver_win.cpp
@@ -42,9 +42,14 @@
#include "qlocalserver.h"
#include "qlocalserver_p.h"
#include "qlocalsocket.h"
+#include <QtCore/private/qsystemerror_p.h>
#include <qdebug.h>
+#include <Aclapi.h>
+#include <AccCtrl.h>
+#include <Sddl.h>
+
// The buffer size need to be 0 otherwise data could be
// lost if the socket that has written data closes the connection
// before it is read. Pipewriter is used for write buffering.
@@ -62,6 +67,116 @@ bool QLocalServerPrivate::addListener()
listeners << Listener();
Listener &listener = listeners.last();
+ SECURITY_ATTRIBUTES sa;
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = FALSE; //non inheritable handle, same as default
+ sa.lpSecurityDescriptor = 0; //default security descriptor
+
+ QScopedPointer<SECURITY_DESCRIPTOR> pSD;
+ PSID worldSID = 0;
+ QByteArray aclBuffer;
+ QByteArray tokenUserBuffer;
+ QByteArray tokenGroupBuffer;
+
+ // create security descriptor if access options were specified
+ if ((socketOptions & QLocalServer::WorldAccessOption)) {
+ pSD.reset(new SECURITY_DESCRIPTOR);
+ if (!InitializeSecurityDescriptor(pSD.data(), SECURITY_DESCRIPTOR_REVISION)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ return false;
+ }
+ HANDLE hToken = NULL;
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
+ return false;
+ DWORD dwBufferSize = 0;
+ GetTokenInformation(hToken, TokenUser, 0, 0, &dwBufferSize);
+ tokenUserBuffer.fill(0, dwBufferSize);
+ PTOKEN_USER pTokenUser = (PTOKEN_USER)tokenUserBuffer.data();
+ if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwBufferSize)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ CloseHandle(hToken);
+ return false;
+ }
+
+ dwBufferSize = 0;
+ GetTokenInformation(hToken, TokenPrimaryGroup, 0, 0, &dwBufferSize);
+ tokenGroupBuffer.fill(0, dwBufferSize);
+ PTOKEN_PRIMARY_GROUP pTokenGroup = (PTOKEN_PRIMARY_GROUP)tokenGroupBuffer.data();
+ if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dwBufferSize, &dwBufferSize)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ CloseHandle(hToken);
+ return false;
+ }
+ CloseHandle(hToken);
+
+#ifdef QLOCALSERVER_DEBUG
+ DWORD groupNameSize;
+ DWORD domainNameSize;
+ SID_NAME_USE groupNameUse;
+ LPWSTR groupNameSid;
+ LookupAccountSid(0, pTokenGroup->PrimaryGroup, 0, &groupNameSize, 0, &domainNameSize, &groupNameUse);
+ QScopedPointer<wchar_t, QScopedPointerArrayDeleter<wchar_t>> groupName(new wchar_t[groupNameSize]);
+ QScopedPointer<wchar_t, QScopedPointerArrayDeleter<wchar_t>> domainName(new wchar_t[domainNameSize]);
+ if (LookupAccountSid(0, pTokenGroup->PrimaryGroup, groupName.data(), &groupNameSize, domainName.data(), &domainNameSize, &groupNameUse)) {
+ qDebug() << "primary group" << QString::fromWCharArray(domainName.data()) << "\\" << QString::fromWCharArray(groupName.data()) << "type=" << groupNameUse;
+ }
+ if (ConvertSidToStringSid(pTokenGroup->PrimaryGroup, &groupNameSid)) {
+ qDebug() << "primary group SID" << QString::fromWCharArray(groupNameSid) << "valid" << IsValidSid(pTokenGroup->PrimaryGroup);
+ LocalFree(groupNameSid);
+ }
+#endif
+
+ SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
+ if (!AllocateAndInitializeSid(&WorldAuth, 1, SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &worldSID)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ return false;
+ }
+
+ //calculate size of ACL buffer
+ DWORD aclSize = sizeof(ACL) + ((sizeof(ACCESS_ALLOWED_ACE)) * 3);
+ aclSize += GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD);
+ aclSize += GetLengthSid(pTokenGroup->PrimaryGroup) - sizeof(DWORD);
+ aclSize += GetLengthSid(worldSID) - sizeof(DWORD);
+ aclSize = (aclSize + (sizeof(DWORD) - 1)) & 0xfffffffc;
+
+ aclBuffer.fill(0, aclSize);
+ PACL acl = (PACL)aclBuffer.data();
+ InitializeAcl(acl, aclSize, ACL_REVISION_DS);
+
+ if (socketOptions & QLocalServer::UserAccessOption) {
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenUser->User.Sid)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ FreeSid(worldSID);
+ return false;
+ }
+ }
+ if (socketOptions & QLocalServer::GroupAccessOption) {
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, pTokenGroup->PrimaryGroup)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ FreeSid(worldSID);
+ return false;
+ }
+ }
+ if (socketOptions & QLocalServer::OtherAccessOption) {
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, FILE_ALL_ACCESS, worldSID)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ FreeSid(worldSID);
+ return false;
+ }
+ }
+ SetSecurityDescriptorOwner(pSD.data(), pTokenUser->User.Sid, FALSE);
+ SetSecurityDescriptorGroup(pSD.data(), pTokenGroup->PrimaryGroup, FALSE);
+ if (!SetSecurityDescriptorDacl(pSD.data(), TRUE, acl, FALSE)) {
+ setError(QLatin1String("QLocalServerPrivate::addListener"));
+ FreeSid(worldSID);
+ return false;
+ }
+
+ sa.lpSecurityDescriptor = pSD.data();
+ }
+
listener.handle = CreateNamedPipe(
(const wchar_t *)fullServerName.utf16(), // pipe name
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, // read/write access
@@ -72,7 +187,7 @@ bool QLocalServerPrivate::addListener()
BUFSIZE, // output buffer size
BUFSIZE, // input buffer size
3000, // client time-out
- NULL);
+ &sa);
if (listener.handle == INVALID_HANDLE_VALUE) {
setError(QLatin1String("QLocalServerPrivate::addListener"));
@@ -80,6 +195,9 @@ bool QLocalServerPrivate::addListener()
return false;
}
+ if (worldSID)
+ FreeSid(worldSID);
+
memset(&listener.overlapped, 0, sizeof(listener.overlapped));
listener.overlapped.hEvent = eventHandle;
if (!ConnectNamedPipe(listener.handle, &listener.overlapped)) {