// Copyright 2005-2019 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "ACL.h" #include "Channel.h" #include "Group.h" #include "User.h" #ifdef MURMUR #include "ServerUser.h" #include #endif ChanACL::ChanACL(Channel *chan) : QObject(chan) { bApplyHere = true; bApplySubs = true; bInherited = false; iUserId = -1; c = chan; if (c) c->qlACL << this; } // Check permissions. // This will always return true for the superuser, // and will return false if a user isn't allowed to // traverse to the channel. (Need "read" in all preceeding channels) #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) { // Superuser if (p->iId == 0) { return static_cast(All &~ (Speak|Whisper)); } Permissions granted = 0; if (cache) { QHash *h = cache->value(p); if (h) granted = h->value(chan); } if (granted & Cached) { return granted; } QStack chanstack; Channel *ch = chan; while (ch) { chanstack.push(ch); ch = ch->cParent; } // Default permissions Permissions def = Traverse | Enter | Speak | Whisper | TextMessage; granted = def; bool traverse = true; bool write = false; ChanACL *acl; while (! chanstack.isEmpty()) { ch = chanstack.pop(); if (! ch->bInheritACL) granted = def; foreach(acl, ch->qlACL) { bool matchUser = (acl->iUserId != -1) && (acl->iUserId == p->iId); bool matchGroup = Group::isMember(chan, ch, acl->qsGroup, p); if (matchUser || matchGroup) { if (acl->pAllow & Traverse) traverse = true; if (acl->pDeny & Traverse) traverse = false; if (acl->pAllow & Write) 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 & ~(Kick|Ban|Register|SelfRegister|Cached)); granted &= ~acl->pDeny; } } } if (! traverse && ! write) { granted = None; break; } } if (granted & Write) { granted |= Traverse|Enter|MuteDeafen|Move|MakeChannel|LinkChannel|TextMessage|MakeTempChannel; if (chan->iId == 0) granted |= Kick|Ban|Register|SelfRegister; } if (cache) { if (! cache->contains(p)) cache->insert(p, new QHash); cache->value(p)->insert(chan, granted | Cached); } return granted; } #else QString ChanACL::whatsThis(Perm p) { switch (p) { case None: return tr("This represents no privileges."); case Write: return tr("This represents total access to the channel, including the ability to change group and ACL information. " "This privilege implies all other privileges."); case Traverse: return tr("This represents the permission to traverse the channel. If a user is denied this privilege, he will be " "unable to access this channel and any sub-channels in any way, regardless of other permissions in the " "sub-channels."); case Enter: return tr("This represents the permission to join the channel. If you have a hierarchical channel structure, you " "might want to give everyone Traverse, but restrict Enter in the root of your hierarchy."); case Speak: return tr("This represents the permission to speak in a channel. Users without this privilege will be suppressed by " "the server (seen as muted), and will be unable to speak until they are unmuted by someone with the " "appropriate privileges."); case Whisper: return tr("This represents the permission to whisper to this channel from the outside. This works exactly like the speak " "privilege, but applies to packets spoken with the Whisper key held down. This may be used to broadcast to a hierarchy " "of channels without linking."); case MuteDeafen: return tr("This represents the permission to mute and deafen other users. Once muted, a user will stay muted " "until he is unmuted by another privileged user or reconnects to the server."); case Move: return tr("This represents the permission to move a user to another channel or kick him from the server. To actually " "move the user, either the moving user must have Move privileges in the destination channel, or " "the user must normally be allowed to enter the channel. Users with this privilege can move users " "into channels the target user normally wouldn't have permission to enter."); case MakeChannel: return tr("This represents the permission to make sub-channels. The user making the sub-channel will be added to the " "admin group of the sub-channel."); case MakeTempChannel: return tr("This represents the permission to make a temporary subchannel. The user making the sub-channel will be added to the " "admin group of the sub-channel. Temporary channels are not stored and disappear when the last user leaves."); case LinkChannel: return tr("This represents the permission to link channels. Users in linked channels hear each other, as long as " "the speaking user has the speak privilege in the channel of the listener. You need the link " "privilege in both channels to create a link, but just in either channel to remove it."); case TextMessage: return tr("This represents the permission to write text messages to other users in this channel."); case Kick: return tr("This represents the permission to forcibly remove users from the server."); case Ban: return tr("This represents the permission to permanently remove users from the server."); case Register: return tr("This represents the permission to register and unregister users on the server."); case SelfRegister: return tr("This represents the permission to register oneself on the server."); default: break; } return QString(); } #endif QString ChanACL::permName(QFlags p) { QStringList qsl; for (int i=0;i<=31;++i) { if (p & (1<(1<