diff --git a/src/ACL.cpp b/src/ACL.cpp index 108d0cf3f..2785f83f0 100644 --- a/src/ACL.cpp +++ b/src/ACL.cpp @@ -57,19 +57,20 @@ ChanACL::ChanACL(Channel *chan) : QObject(chan) { #ifdef MURMUR bool ChanACL::hasPermission(ServerUser *p, Channel *chan, QFlags perm, ACLCache &cache) { + Permissions granted = effectivePermissions(p, chan, cache); + + return ((granted & perm) != None); +} + +// Return effective permissions. +QFlags ChanACL::effectivePermissions(ServerUser *p, Channel *chan, ACLCache &cache) { QStack chanstack; Channel *ch; ChanACL *acl; // Superuser if (p->iId == 0) { - switch (perm) { - case Speak: - case Whisper: - return false; - default: - return true; - } + return static_cast(All &~ (Speak|Whisper)); } Permissions granted = 0; @@ -79,10 +80,7 @@ bool ChanACL::hasPermission(ServerUser *p, Channel *chan, QFlags perm, ACL granted = h->value(chan); if (granted & Cached) { - if ((perm != Speak) && (perm != Whisper)) - return ((granted & (perm | Write)) != None); - else - return ((granted & perm) != None); + return granted; } ch = chan; @@ -116,8 +114,18 @@ bool ChanACL::hasPermission(ServerUser *p, Channel *chan, QFlags perm, ACL write = true; if (acl->pDeny & Write) write = false; + if (ch->iId == 0 && chan == ch && acl->bApplyHere) { + if (acl->pAllow & Kick) + granted |= Kick; + if (acl->pAllow & Ban) + granted |= Ban; + if (acl->pAllow & Register) + granted |= Register; + if (acl->pAllow & SelfRegister) + granted |= SelfRegister; + } if ((ch==chan && acl->bApplyHere) || (ch!=chan && acl->bApplySubs)) { - granted |= acl->pAllow; + granted |= (acl->pAllow & ~(Kick|Ban|Register|SelfRegister|Cached)); granted &= ~acl->pDeny; } } @@ -128,15 +136,19 @@ bool ChanACL::hasPermission(ServerUser *p, Channel *chan, QFlags perm, ACL } } + if (granted & Write) { + granted |= Traverse|Enter|MuteDeafen|Move|MakeChannel|LinkChannel|TextMessage|MakeTempChannel; + if (chan->iId == 0) + granted |= Kick|Ban|Register|SelfRegister; + } + + if (! cache.contains(p)) cache.insert(p, new QHash); cache.value(p)->insert(chan, granted | Cached); - if ((perm != Speak) && (perm != Whisper)) - return ((granted & (perm | Write)) != None); - else - return ((granted & perm) != None); + return granted; } #else diff --git a/src/ACL.h b/src/ACL.h index 988effe46..7883afdf4 100644 --- a/src/ACL.h +++ b/src/ACL.h @@ -85,6 +85,7 @@ class ChanACL : public QObject { ChanACL(Channel *c); #ifdef MURMUR static bool hasPermission(ServerUser *p, Channel *c, QFlags perm, ACLCache &cache); + static QFlags effectivePermissions(ServerUser *p, Channel *c, ACLCache &cache); #else static QString whatsThis(Perm p); #endif diff --git a/src/murmur/Murmur.ice b/src/murmur/Murmur.ice index 12fb6b29e..dd10f5508 100644 --- a/src/murmur/Murmur.ice +++ b/src/murmur/Murmur.ice @@ -575,6 +575,13 @@ module Murmur * @return true if any of the permissions in perm were set for the user. */ bool hasPermission(int session, int channelid, int perm) throws ServerBootedException, InvalidSessionException, InvalidChannelException, InvalidSecretException; + + /** Return users effective permissions + * @param session Connection ID of user. See {@link User.session}. + * @param channelid ID of Channel. See {@link Channel.id}. + * @return bitfield of allowed actions + */ + idempotent int effectivePermissions(int session, int channelid) throws ServerBootedException, InvalidSessionException, InvalidChannelException, InvalidSecretException; /** Add a context callback. This is done per user, and will add a context menu action for the user. * diff --git a/src/murmur/MurmurI.h b/src/murmur/MurmurI.h index abcc825aa..d352f76dc 100644 --- a/src/murmur/MurmurI.h +++ b/src/murmur/MurmurI.h @@ -83,6 +83,7 @@ namespace Murmur { const Ice::Current&); virtual void hasPermission_async(const ::Murmur::AMD_Server_hasPermissionPtr&, ::Ice::Int, ::Ice::Int, ::Ice::Int, const ::Ice::Current&); + virtual void effectivePermissions_async(const ::Murmur::AMD_Server_effectivePermissionsPtr&, ::Ice::Int, ::Ice::Int, const ::Ice::Current&); virtual void addContextCallback_async(const ::Murmur::AMD_Server_addContextCallbackPtr&, ::Ice::Int, const ::std::string&, const ::std::string&, const ::Murmur::ServerContextCallbackPrx&, int, const ::Ice::Current&); virtual void removeContextCallback_async(const ::Murmur::AMD_Server_removeContextCallbackPtr&, const ::Murmur::ServerContextCallbackPrx&, const ::Ice::Current&); diff --git a/src/murmur/MurmurIce.cpp b/src/murmur/MurmurIce.cpp index 0d272ae06..c1d5c823c 100644 --- a/src/murmur/MurmurIce.cpp +++ b/src/murmur/MurmurIce.cpp @@ -1019,6 +1019,14 @@ static void impl_Server_hasPermission(const ::Murmur::AMD_Server_hasPermissionPt cb->ice_response(server->hasPermission(user, channel, static_cast(perm))); } +#define ACCESS_Server_effectivePermissions_READ +static void impl_Server_effectivePermissions(const ::Murmur::AMD_Server_effectivePermissionsPtr cb, int server_id, ::Ice::Int session, ::Ice::Int channelid) { + NEED_SERVER; + NEED_PLAYER; + NEED_CHANNEL; + cb->ice_response(server->effectivePermissions(user, channel)); +} + static void impl_Server_addContextCallback(const Murmur::AMD_Server_addContextCallbackPtr cb, int server_id, ::Ice::Int session, const ::std::string& action, const ::std::string& text, const ::Murmur::ServerContextCallbackPrx& cbptr, int ctx) { NEED_SERVER; NEED_PLAYER; diff --git a/src/murmur/MurmurIceWrapper.cpp b/src/murmur/MurmurIceWrapper.cpp index 87286f071..8fe93a87a 100644 --- a/src/murmur/MurmurIceWrapper.cpp +++ b/src/murmur/MurmurIceWrapper.cpp @@ -749,6 +749,36 @@ void ::Murmur::ServerI::hasPermission_async(const ::Murmur::AMD_Server_hasPermis QCoreApplication::instance()->postEvent(mi, ie); } +void ::Murmur::ServerI::effectivePermissions_async(const ::Murmur::AMD_Server_effectivePermissionsPtr &cb, ::Ice::Int p1, ::Ice::Int p2, const ::Ice::Current ¤t) { + // qWarning() << effectivePermissions << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty(); +#ifndef ACCESS_Server_effectivePermissions_ALL +#ifdef ACCESS_Server_effectivePermissions_READ + if ( !meta->mp.qsIceSecretRead.isNull()) { + bool ok = ! meta->mp.qsIceSecretRead.isEmpty(); +#else + if (! meta->mp.qsIceSecretRead.isNull() ||! meta->mp.qsIceSecretWrite.isNull()) { + bool ok = ! meta->mp.qsIceSecretWrite.isEmpty(); +#endif + ::Ice::Context::const_iterator i = current.ctx.find("secret"); + ok = ok && (i != current.ctx.end()); + if (ok) { + const QString &secret = u8((*i).second); +#ifdef ACCESS_Server_effectivePermissions_READ + ok = ((secret == meta->mp.qsIceSecretRead) ||(secret == meta->mp.qsIceSecretWrite)); +#else + ok = (secret == meta->mp.qsIceSecretWrite); +#endif + } + if (! ok) { + cb->ice_exception(InvalidSecretException()); + return; + } + } +#endif + ExecEvent *ie = new ExecEvent(boost::bind(&impl_Server_effectivePermissions, cb, QString::fromStdString(current.id.name).toInt(), p1, p2)); + QCoreApplication::instance()->postEvent(mi, ie); +} + void ::Murmur::ServerI::addContextCallback_async(const ::Murmur::AMD_Server_addContextCallbackPtr &cb, ::Ice::Int p1, const ::std::string& p2, const ::std::string& p3, const ::Murmur::ServerContextCallbackPrx& p4, ::Ice::Int p5, const ::Ice::Current ¤t) { // qWarning() << "addContextCallback" << meta->mp.qsIceSecretRead.isNull() << meta->mp.qsIceSecretRead.isEmpty(); #ifndef ACCESS_Server_addContextCallback_ALL diff --git a/src/murmur/Server.cpp b/src/murmur/Server.cpp index 81ff3bdef..f649a7f2d 100644 --- a/src/murmur/Server.cpp +++ b/src/murmur/Server.cpp @@ -1491,6 +1491,11 @@ bool Server::hasPermission(ServerUser *p, Channel *c, QFlags perm return ChanACL::hasPermission(p, c, perm, acCache); } +QFlags Server::effectivePermissions(ServerUser *p, Channel *c) { + QMutexLocker qml(&qmCache); + return ChanACL::effectivePermissions(p, c, acCache); +} + void Server::sendClientPermission(ServerUser *u, Channel *c, bool forceupdate) { unsigned int perm; diff --git a/src/murmur/Server.h b/src/murmur/Server.h index 8aa9ad058..98c1cab85 100644 --- a/src/murmur/Server.h +++ b/src/murmur/Server.h @@ -220,6 +220,7 @@ class Server : public QThread { bool checkDecrypt(ServerUser *u, const char *encrypted, char *plain, unsigned int cryptlen); bool hasPermission(ServerUser *p, Channel *c, QFlags perm); + QFlags effectivePermissions(ServerUser *p, Channel *c); void sendClientPermission(ServerUser *u, Channel *c, bool updatelast = false); void flushClientPermissionCache(ServerUser *u, MumbleProto::PermissionQuery &mpqq); void clearACLCache(User *p = NULL);