diff --git a/src/Mumble.proto b/src/Mumble.proto index 68c1ae094..cf8bf15c4 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -213,6 +213,8 @@ message UserState { optional bool priority_speaker = 18; // True if the user is currently recording. optional bool recording = 19; + // a list of temporary acces tokens to be respected when processing this request + repeated string temporary_access_tokens = 20; } // Relays information on the bans. The client may send the BanList message to diff --git a/src/mumble/ServerHandler.cpp b/src/mumble/ServerHandler.cpp index b5606acef..3a8078562 100644 --- a/src/mumble/ServerHandler.cpp +++ b/src/mumble/ServerHandler.cpp @@ -816,9 +816,20 @@ void ServerHandler::requestUserStats(unsigned int uiSession, bool statsOnly) { } void ServerHandler::joinChannel(unsigned int uiSession, unsigned int channel) { + static const QStringList EMPTY; + + joinChannel(uiSession, channel, EMPTY); +} + +void ServerHandler::joinChannel(unsigned int uiSession, unsigned int channel, const QStringList &temporaryAccessTokens) { MumbleProto::UserState mpus; mpus.set_session(uiSession); mpus.set_channel_id(channel); + + foreach(QString tmpToken, temporaryAccessTokens) { + mpus.add_temporary_access_tokens(tmpToken.toUtf8().constData()); + } + sendMessage(mpus); } diff --git a/src/mumble/ServerHandler.h b/src/mumble/ServerHandler.h index 045e55f45..ae5c95851 100644 --- a/src/mumble/ServerHandler.h +++ b/src/mumble/ServerHandler.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -117,6 +118,7 @@ class ServerHandler : public QThread { void requestUserStats(unsigned int uiSession, bool statsOnly); void joinChannel(unsigned int uiSession, unsigned int channel); + void joinChannel(unsigned int uiSession, unsigned int channel, const QStringList &temporaryAccessTokens); void createChannel(unsigned int parent_id, const QString &name, const QString &description, unsigned int position, bool temporary, unsigned int maxUsers); void requestBanList(); void requestUserList(); diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index c2ae3e769..1b67b298e 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -77,6 +77,59 @@ sendMessage(uSource, mppd); \ } +/// A helper class for managing temporary access tokens +/// It will add the tokens in the comstructor and remove them again in the destructor effectively +/// turning the tokens into a scope-based property +class TemporaryAccessTokenHelper { + protected: + ServerUser *affectedUser; + QStringList qslTemporaryTokens; + Server *server; + + public: + TemporaryAccessTokenHelper(ServerUser *affectedUser, const QStringList &tokens, Server *server) : affectedUser(affectedUser), + qslTemporaryTokens(tokens), server(server) { + // Add the temporary tokens + QMutableStringListIterator it(this->qslTemporaryTokens); + + { + QMutexLocker qml(&server->qmCache); + + while (it.hasNext()) { + QString token = it.next(); + if (!this->affectedUser->qslAccessTokens.contains(token)) { + // Add token + this->affectedUser->qslAccessTokens << token; + } else { + // It appears, as if the user already has this token set -> it's not a temporary one or a duplicate + it.remove(); + } + } + } + + if (!this->qslTemporaryTokens.isEmpty()) { + // Clear the cache in order for tokens to take effect + server->clearACLCache(this->affectedUser); + } + } + + ~TemporaryAccessTokenHelper() { + if (!this->qslTemporaryTokens.isEmpty()) { + { + QMutexLocker qml(&server->qmCache); + + // remove the temporary tokens + foreach(QString token, this->qslTemporaryTokens) { + this->affectedUser->qslAccessTokens.removeOne(token); + } + } + + // Clear cache to actually get rid of the temporary tokens + server->clearACLCache(this->affectedUser); + } + } +}; + void Server::msgAuthenticate(ServerUser *uSource, MumbleProto::Authenticate &msg) { if ((msg.tokens_size() > 0) || (uSource->sState == ServerUser::Authenticated)) { QStringList qsl; @@ -501,6 +554,7 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { First check all permissions involved */ if ((pDstServerUser->iId == 0) && (uSource->iId != 0)) { + // Don't allow any action on the SuperUser except initiated directly by the SuperUser himself/herself PERM_DENIED_TYPE(SuperUser); return; } @@ -516,6 +570,13 @@ void Server::msgUserState(ServerUser *uSource, MumbleProto::UserState &msg) { if (uSource == pDstServerUser) { RATELIMIT(uSource); } + + // Handle potential temporary access tokens + QStringList temporaryAccessTokens; + for (int i=0; i < msg.temporary_access_tokens_size(); i++) { + temporaryAccessTokens << u8(msg.temporary_access_tokens(i)); + } + TemporaryAccessTokenHelper tempTokenHelper(uSource, temporaryAccessTokens, this); if (msg.has_channel_id()) { Channel *c = qhChannels.value(msg.channel_id());