diff options
author | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-10-14 01:53:47 +0400 |
---|---|---|
committer | Thorvald Natvig <slicer@users.sourceforge.net> | 2009-10-14 01:54:34 +0400 |
commit | 7439bc4fe6b423ff0d36d3b1d529e474c14e9b01 (patch) | |
tree | 5b0e3edeb898e52f01d20e1c80fd342b9a3e5b97 /src | |
parent | 56f5f978c0e434b4883e9d96d6886d112cde2afc (diff) |
Permission query (serverside)
Diffstat (limited to 'src')
-rw-r--r-- | src/Message.h | 3 | ||||
-rw-r--r-- | src/Mumble.proto | 6 | ||||
-rw-r--r-- | src/murmur/Messages.cpp | 10 | ||||
-rw-r--r-- | src/murmur/Server.cpp | 80 | ||||
-rw-r--r-- | src/murmur/Server.h | 7 |
5 files changed, 103 insertions, 3 deletions
diff --git a/src/Message.h b/src/Message.h index 4eee97d69..1a9572fe9 100644 --- a/src/Message.h +++ b/src/Message.h @@ -54,7 +54,8 @@ MUMBLE_MH_MSG(ContextActionAdd) \ MUMBLE_MH_MSG(ContextAction) \ MUMBLE_MH_MSG(UserList) \ - MUMBLE_MH_MSG(VoiceTarget) + MUMBLE_MH_MSG(VoiceTarget) \ + MUMBLE_MH_MSG(PermissionQuery) class MessageHandler { public: diff --git a/src/Mumble.proto b/src/Mumble.proto index eb81c589c..511db13a3 100644 --- a/src/Mumble.proto +++ b/src/Mumble.proto @@ -208,3 +208,9 @@ message VoiceTarget { optional uint32 id = 1; repeated Target targets = 2; } + +message PermissionQuery { + optional uint32 channel_id = 1; + optional uint32 permissions = 2; + optional bool flush = 3 [default = false]; +} diff --git a/src/murmur/Messages.cpp b/src/murmur/Messages.cpp index d1c233728..153636844 100644 --- a/src/murmur/Messages.cpp +++ b/src/murmur/Messages.cpp @@ -1275,3 +1275,13 @@ void Server::msgVoiceTarget(ServerUser *uSource, MumbleProto::VoiceTarget &msg) uSource->qmTargets.insert(target, wt); } } + +void Server::msgPermissionQuery(ServerUser *uSource, MumbleProto::PermissionQuery &msg) { + MSG_SETUP(ServerUser::Authenticated); + + Channel *c = qhChannels.value(msg.channel_id()); + if (!c) + return; + + sendClientPermission(uSource, c, true); +} diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index dbc649a3f..bf30f6f77 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -80,6 +80,7 @@ ServerUser::ServerUser(Server *p, QSslSocket *socket) : Connection(p, socket), U bUdp = true; uiVersion = 0; bVerified = true; + iLastPermissionCheck = -1; } @@ -1304,6 +1305,8 @@ void Server::userEnterChannel(User *p, Channel *c, bool quiet, bool ignoretemp) if (old && old->bTemporary && old->qlUsers.isEmpty() && ! ignoretemp) { QCoreApplication::instance()->postEvent(this, new ExecEvent(boost::bind(&Server::removeChannel, this, old->iId))); } + + sendClientPermission(static_cast<ServerUser *>(p), c); } bool Server::hasPermission(ServerUser *p, Channel *c, QFlags<ChanACL::Perm> perm) { @@ -1311,7 +1314,78 @@ bool Server::hasPermission(ServerUser *p, Channel *c, QFlags<ChanACL::Perm> perm return ChanACL::hasPermission(p, c, perm, acCache); } +void Server::sendClientPermission(ServerUser *u, Channel *c, bool forceupdate) { + unsigned int perm; + + { + QMutexLocker qml(&qmCache); + ChanACL::hasPermission(u, c, ChanACL::Enter, acCache); + perm = acCache.value(u)->value(c); + } + + if (forceupdate) + u->iLastPermissionCheck = c->iId; + + if (u->qmPermissionSent.value(c->iId) != perm) { + u->qmPermissionSent.insert(c->iId, perm); + + MumbleProto::PermissionQuery mppq; + mppq.set_channel_id(c->iId); + mppq.set_permissions(perm); + + sendMessage(u, mppq); + } +} + +/* This function is a helper for clearACLCache and assumes qmCache is held. + * First, check if anything actually changed, or if the list is getting awfully large, + * because this function is potentially quite expensive. + * If all the items are still valid; great. If they aren't, send off the last channel + * the client expliticly asked for -- this may not be what it wants, but it's our best + * guess. + */ + +void Server::flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mppq) { + QMap<int, unsigned int>::const_iterator i; + bool match = (u->qmPermissionSent.count() < 20); + for(i = u->qmPermissionSent.constBegin(); (match && (i != u->qmPermissionSent.constEnd())); ++i) { + Channel *c = qhChannels.value(i.key()); + if (! c) { + match = false; + } else { + ChanACL::hasPermission(u, c, ChanACL::Enter, acCache); + unsigned int perm = acCache.value(u)->value(c); + if (perm != i.value()) + match = false; + } + } + + if (match) + return; + + u->qmPermissionSent.clear(); + + Channel *c = qhChannels.value(u->iLastPermissionCheck); + if (! c) { + c = u->cChannel; + u->iLastPermissionCheck = c->iId; + } + + ChanACL::hasPermission(u, c, ChanACL::Enter, acCache); + unsigned int perm = acCache.value(u)->value(c); + u->qmPermissionSent.insert(c->iId, perm); + + mppq.Clear(); + mppq.set_channel_id(c->iId); + mppq.set_permissions(perm); + mppq.set_flush(true); + + sendMessage(u, mppq); +} + void Server::clearACLCache(User *p) { + MumbleProto::PermissionQuery mppq; + { QMutexLocker qml(&qmCache); @@ -1319,10 +1393,16 @@ void Server::clearACLCache(User *p) { ChanACL::ChanCache *h = acCache.take(p); if (h) delete h; + + flushClientPermissionCache(static_cast<ServerUser *>(p), mppq); } else { foreach(ChanACL::ChanCache *h, acCache) delete h; acCache.clear(); + + foreach(ServerUser *u, qhUsers) + if (u->sState == ServerUser::Authenticated) + flushClientPermissionCache(u, mppq); } } diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 6bb273719..90ea9227d 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -153,13 +153,14 @@ class ServerUser : public Connection, public User { typedef QPair<QSet<ServerUser *>, QSet<ServerUser *> > TargetCache; QMap<int, TargetCache> qmTargetCache; QMap<QString, QString> qmWhisperRedirect; - + + int iLastPermissionCheck; + QMap<int, unsigned int> qmPermissionSent; #ifdef Q_OS_UNIX int sUdpSocket; #else SOCKET sUdpSocket; #endif - BandwidthRecord bwr; struct sockaddr_storage saiUdpAddress; ServerUser(Server *parent, QSslSocket *socket); @@ -282,6 +283,8 @@ class Server : public QThread { bool checkDecrypt(ServerUser *u, const char *encrypted, char *plain, unsigned int cryptlen); bool hasPermission(ServerUser *p, Channel *c, QFlags<ChanACL::Perm> perm); + void sendClientPermission(ServerUser *u, Channel *c, bool updatelast = false); + void flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mpqq); void clearACLCache(User *p = NULL); void sendProtoAll(const ::google::protobuf::Message &msg, unsigned int msgType); |