summaryrefslogtreecommitdiffstats
path: root/src/network
diff options
context:
space:
mode:
Diffstat (limited to 'src/network')
-rw-r--r--src/network/socket/qlocalserver.cpp63
-rw-r--r--src/network/socket/qlocalserver.h16
-rw-r--r--src/network/socket/qlocalserver_p.h4
-rw-r--r--src/network/socket/qlocalserver_unix.cpp65
4 files changed, 145 insertions, 3 deletions
diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp
index b3fe4ac448..97f5920171 100644
--- a/src/network/socket/qlocalserver.cpp
+++ b/src/network/socket/qlocalserver.cpp
@@ -82,6 +82,27 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \enum QLocalServer::SocketOption
+
+ This enum describes the possible options that can be used to create the
+ socket. This changes the access permissions on platforms (Linux, Windows)
+ that support access permissions on the socket. Both GroupAccess and OtherAccess
+ may vary slightly in meanings depending on the platform.
+
+ \value UserAccess
+ Access is restricted to the same user as the process that created the socket.
+ \value GroupAccess
+ Access is restricted to the same group but not the user that created the socket on Linux.
+ \value OtherAccess
+ Access is available to everyone but the user and group that created the socket on Linux.
+ \value WorldAccess
+ No access restrictions.
+
+ \sa SocketOptions
+*/
+
+
+/*!
Create a new local socket server with the given \a parent.
\sa listen()
@@ -109,6 +130,48 @@ QLocalServer::~QLocalServer()
}
/*!
+ \property QLocalServer::socketOptions
+ \since 5.0
+
+ The setSocketOptions method controls how the socket operates.
+ For example the socket may restrict access to what user ids can
+ connect to the socket.
+
+ These options must be set before listen() is called.
+
+ In some cases, such as with Unix domain sockets on Linux, the
+ access to the socket will be determined by file system permissions,
+ and are created based on the umask. Setting the access flags will
+ overide this and will restrict or permit access as specified.
+
+ Other Unix-based operating systems, such as Mac OS X, do not
+ honor file permissions for Unix domain sockets and by default
+ have WorldAccess and these permission flags will have no effect.
+
+ By default none of the flags are set, access permissions
+ are the platform default.
+
+ \sa listen()
+*/
+void QLocalServer::setSocketOptions(SocketOptions options)
+{
+ Q_D(QLocalServer);
+
+ d->socketOptions = options;
+}
+
+/*!
+ Returns the socket options set on the socket.
+
+ \sa setSocketOptions()
+ */
+QLocalServer::SocketOptions QLocalServer::socketOptions() const
+{
+ Q_D(const QLocalServer);
+ return d->socketOptions;
+}
+
+/*!
Stop listening for incoming connections. Existing connections are not
effected, but any new connections will be refused.
diff --git a/src/network/socket/qlocalserver.h b/src/network/socket/qlocalserver.h
index f694131953..6f883adc24 100644
--- a/src/network/socket/qlocalserver.h
+++ b/src/network/socket/qlocalserver.h
@@ -58,11 +58,22 @@ class Q_NETWORK_EXPORT QLocalServer : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QLocalServer)
+ Q_PROPERTY(SocketOptions socketOptions READ socketOptions WRITE setSocketOptions)
+ Q_FLAGS(SocketOption SocketOptions)
Q_SIGNALS:
void newConnection();
public:
+ enum SocketOption {
+ NoOptions = 0x0,
+ UserAccessOption = 0x01,
+ GroupAccessOption = 0x2,
+ OtherAccessOption = 0x4,
+ WorldAccessOption = 0x7
+ };
+ Q_DECLARE_FLAGS(SocketOptions, SocketOption)
+
QLocalServer(QObject *parent = 0);
~QLocalServer();
@@ -80,6 +91,9 @@ public:
void setMaxPendingConnections(int numConnections);
bool waitForNewConnection(int msec = 0, bool *timedOut = 0);
+ void setSocketOptions(SocketOptions options);
+ SocketOptions socketOptions() const;
+
protected:
virtual void incomingConnection(quintptr socketDescriptor);
@@ -88,6 +102,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_onNewConnection())
};
+Q_DECLARE_OPERATORS_FOR_FLAGS(QLocalServer::SocketOptions)
+
#endif // QT_NO_LOCALSERVER
QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h
index 6e39136dd4..03c06a42e3 100644
--- a/src/network/socket/qlocalserver_p.h
+++ b/src/network/socket/qlocalserver_p.h
@@ -80,7 +80,8 @@ public:
#if !defined(QT_LOCALSOCKET_TCP) && !defined(Q_OS_WIN)
listenSocket(-1), socketNotifier(0),
#endif
- maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError)
+ maxPendingConnections(30), error(QAbstractSocket::UnknownSocketError),
+ socketOptions(QLocalServer::NoOptions)
{
}
@@ -121,6 +122,7 @@ public:
QQueue<QLocalSocket*> pendingConnections;
QString errorString;
QAbstractSocket::SocketError error;
+ QLocalServer::SocketOptions socketOptions;
};
QT_END_NAMESPACE
diff --git a/src/network/socket/qlocalserver_unix.cpp b/src/network/socket/qlocalserver_unix.cpp
index c4482dadfc..ce0c283f0b 100644
--- a/src/network/socket/qlocalserver_unix.cpp
+++ b/src/network/socket/qlocalserver_unix.cpp
@@ -44,6 +44,7 @@
#include "qlocalsocket.h"
#include "qlocalsocket_p.h"
#include "qnet_unix_p.h"
+#include "qtemporarydir.h"
#ifndef QT_NO_LOCALSERVER
@@ -92,6 +93,20 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
}
serverName = requestedServerName;
+ QString tempPath;
+ QScopedPointer<QTemporaryDir> tempDir;
+
+ // Check any of the flags
+ if (socketOptions & QLocalServer::WorldAccessOption) {
+ tempDir.reset(new QTemporaryDir(fullServerName));
+ if (!tempDir->isValid()) {
+ setError(QLatin1String("QLocalServer::listen"));
+ return false;
+ }
+ tempPath = tempDir->path();
+ tempPath += QLatin1Char('/') + requestedServerName;
+ }
+
// create the unix socket
listenSocket = qt_safe_socket(PF_UNIX, SOCK_STREAM, 0);
if (-1 == listenSocket) {
@@ -108,8 +123,26 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
closeServer();
return false;
}
- ::memcpy(addr.sun_path, fullServerName.toLatin1().data(),
- fullServerName.toLatin1().size() + 1);
+
+ if (socketOptions & QLocalServer::WorldAccessOption) {
+ if (sizeof(addr.sun_path) < (uint)tempPath.toLatin1().size() + 1) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+ ::memcpy(addr.sun_path, tempPath.toLatin1().data(),
+ tempPath.toLatin1().size() + 1);
+
+ if (-1 == ::fchmod(listenSocket, 0)) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+
+ } else {
+ ::memcpy(addr.sun_path, fullServerName.toLatin1().data(),
+ fullServerName.toLatin1().size() + 1);
+ }
// bind
if(-1 == QT_SOCKET_BIND(listenSocket, (sockaddr *)&addr, sizeof(sockaddr_un))) {
@@ -133,6 +166,34 @@ bool QLocalServerPrivate::listen(const QString &requestedServerName)
QFile::remove(fullServerName);
return false;
}
+
+ if (socketOptions & QLocalServer::WorldAccessOption) {
+ mode_t mode = 000;
+
+ if (socketOptions & QLocalServer::UserAccessOption) {
+ mode |= S_IRWXU;
+ }
+ if (socketOptions & QLocalServer::GroupAccessOption) {
+ mode |= S_IRWXG;
+ }
+ if (socketOptions & QLocalServer::OtherAccessOption) {
+ mode |= S_IRWXO;
+ }
+
+ if (mode) {
+ if (-1 == ::chmod(tempPath.toLatin1(), mode)) {
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+ }
+ if (-1 == ::rename(tempPath.toLatin1(), fullServerName.toLatin1())){
+ setError(QLatin1String("QLocalServer::listen"));
+ closeServer();
+ return false;
+ }
+ }
+
Q_ASSERT(!socketNotifier);
socketNotifier = new QSocketNotifier(listenSocket,
QSocketNotifier::Read, q);