mirror of
https://github.com/mumble-voip/grumble.git
synced 2025-12-19 21:59:59 -08:00
grumble, pkg/acl: move ACL handling to the acl package.
This commit is contained in:
parent
3dc3b25f57
commit
3ef203a83f
12 changed files with 608 additions and 608 deletions
241
acl.go
241
acl.go
|
|
@ -1,241 +0,0 @@
|
||||||
// Copyright (c) 2010 The Grumble Authors
|
|
||||||
// The use of this source code is goverened by a BSD-style
|
|
||||||
// license that can be found in the LICENSE-file.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Per-channel permissions
|
|
||||||
NonePermission = 0x0
|
|
||||||
WritePermission = 0x1
|
|
||||||
TraversePermission = 0x2
|
|
||||||
EnterPermission = 0x4
|
|
||||||
SpeakPermission = 0x8
|
|
||||||
MuteDeafenPermission = 0x10
|
|
||||||
MovePermission = 0x20
|
|
||||||
MakeChannelPermission = 0x40
|
|
||||||
LinkChannelPermission = 0x80
|
|
||||||
WhisperPermission = 0x100
|
|
||||||
TextMessagePermission = 0x200
|
|
||||||
TempChannelPermission = 0x400
|
|
||||||
|
|
||||||
// Root channel only
|
|
||||||
KickPermission = 0x10000
|
|
||||||
BanPermission = 0x20000
|
|
||||||
RegisterPermission = 0x40000
|
|
||||||
SelfRegisterPermission = 0x80000
|
|
||||||
|
|
||||||
// Extra flags
|
|
||||||
CachedPermission = 0x8000000
|
|
||||||
AllPermissions = 0xf07ff
|
|
||||||
)
|
|
||||||
|
|
||||||
type Permission uint32
|
|
||||||
|
|
||||||
// Check whether the given flags are set on perm
|
|
||||||
func (perm Permission) IsSet(check Permission) bool {
|
|
||||||
return perm&check == check
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether the Permission is marked as cached
|
|
||||||
// (i.e. that it was read from an ACLCache)
|
|
||||||
func (perm Permission) IsCached() bool {
|
|
||||||
return perm.IsSet(CachedPermission)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear a flag in the Permission
|
|
||||||
func (perm Permission) ClearFlag(flag Permission) {
|
|
||||||
perm &= ^flag
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the cache bit in the Permission
|
|
||||||
func (perm Permission) ClearCacheBit() {
|
|
||||||
perm.ClearFlag(CachedPermission)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A channel-to-permission mapping used in the ACLCache
|
|
||||||
type ChannelCache map[int]Permission
|
|
||||||
|
|
||||||
// The ACLCache maps a user id to a ChannelCache map.
|
|
||||||
// The ChannelCache map maps a channel to its permissions.
|
|
||||||
type ACLCache map[uint32]ChannelCache
|
|
||||||
|
|
||||||
// Creates a new ACLCache
|
|
||||||
func NewACLCache() ACLCache {
|
|
||||||
return make(map[uint32]ChannelCache)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store a client's permissions for a particular channel. When the permissions are stored,
|
|
||||||
// the permission will have the CachedPermission flag added to it.
|
|
||||||
func (cache ACLCache) StorePermission(client *Client, channel *Channel, perm Permission) {
|
|
||||||
chancache, ok := cache[client.Session]
|
|
||||||
if !ok {
|
|
||||||
chancache = make(map[int]Permission)
|
|
||||||
cache[client.Session] = chancache
|
|
||||||
}
|
|
||||||
chancache[channel.Id] = perm | CachedPermission
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a client's permissions for a partcular channel. NonePermission will be returned
|
|
||||||
// on error. To determine whether the returned value was retrieved from the cache, the
|
|
||||||
// caller must call IsCached() on the returned permission.
|
|
||||||
func (cache ACLCache) GetPermission(client *Client, channel *Channel) (perm Permission) {
|
|
||||||
chancache, ok := cache[client.Session]
|
|
||||||
perm = Permission(NonePermission)
|
|
||||||
if !ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
perm, ok = chancache[channel.Id]
|
|
||||||
if !ok {
|
|
||||||
perm = Permission(NonePermission)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// An ACL as defined on a channel.
|
|
||||||
// An ACL can be defined for either a user or a group.
|
|
||||||
type ChannelACL struct {
|
|
||||||
// The channel that the ChannelACL is defined on.
|
|
||||||
Channel *Channel
|
|
||||||
|
|
||||||
// The user id that this ACL applied to. If this
|
|
||||||
// field is -1, the ACL is a group ACL.
|
|
||||||
UserId int
|
|
||||||
// The group that this ACL applies to.
|
|
||||||
Group string
|
|
||||||
|
|
||||||
// The ApplyHere flag determines whether the ACL
|
|
||||||
// should apply to the current channel.
|
|
||||||
ApplyHere bool
|
|
||||||
// The ApplySubs flag determines whethr the ACL
|
|
||||||
// should apply to subchannels.
|
|
||||||
ApplySubs bool
|
|
||||||
|
|
||||||
// The allowed permission flags.
|
|
||||||
Allow Permission
|
|
||||||
// The allowed permission flags. The Deny flags override
|
|
||||||
// permissions set in Allow.
|
|
||||||
Deny Permission
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the ACL is defined on a user
|
|
||||||
// (as opposed to a group)
|
|
||||||
func (acl ChannelACL) IsUserACL() bool {
|
|
||||||
return acl.UserId != -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true if the ACL is defined on a channel
|
|
||||||
// (as opposed to a user)
|
|
||||||
func (acl ChannelACL) IsChannelACL() bool {
|
|
||||||
return !acl.IsUserACL()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a new ACL for channel. Does not add it to the channel's
|
|
||||||
// ACL list. This must be done manually.
|
|
||||||
func NewChannelACL(channel *Channel) *ChannelACL {
|
|
||||||
return &ChannelACL{
|
|
||||||
Channel: channel,
|
|
||||||
UserId: -1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether client has permission perm on channel. Perm *must* be a single permission,
|
|
||||||
// and not a combination of permissions.
|
|
||||||
func (server *Server) HasPermission(client *Client, channel *Channel, perm Permission) (ok bool) {
|
|
||||||
// SuperUser can't speak or whisper, but everything else is OK
|
|
||||||
if client.IsSuperUser() {
|
|
||||||
if perm == SpeakPermission || perm == WhisperPermission {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// First, try to look in the server's ACLCache.
|
|
||||||
granted := Permission(NonePermission)
|
|
||||||
cached := server.aclcache.GetPermission(client, channel)
|
|
||||||
if cached.IsCached() {
|
|
||||||
granted = cached
|
|
||||||
// The +write permission implies all permissions except for +speak and +whisper.
|
|
||||||
// For more information regarding this check, please see the comment regarding a simmilar
|
|
||||||
// check at the bottom of this function.
|
|
||||||
if perm != SpeakPermission && perm != WhisperPermission {
|
|
||||||
return (granted & (perm | WritePermission)) != NonePermission
|
|
||||||
} else {
|
|
||||||
return (granted & perm) != NonePermission
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default permissions
|
|
||||||
def := Permission(TraversePermission | EnterPermission | SpeakPermission | WhisperPermission | TextMessagePermission)
|
|
||||||
granted = def
|
|
||||||
|
|
||||||
channels := []*Channel{}
|
|
||||||
iter := channel
|
|
||||||
for iter != nil {
|
|
||||||
channels = append([]*Channel{iter}, channels...)
|
|
||||||
iter = iter.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
traverse := true
|
|
||||||
write := false
|
|
||||||
|
|
||||||
for _, iter := range channels {
|
|
||||||
// If the channel does not inherit any ACLs, use the default permissions.
|
|
||||||
if !iter.InheritACL {
|
|
||||||
granted = def
|
|
||||||
}
|
|
||||||
// Iterate through ACLs that are defined on iter. Note: this does not include
|
|
||||||
// ACLs that iter has inherited from a parent (unless there is also a group on
|
|
||||||
// iter with the same name, that changes the permissions a bit!)
|
|
||||||
for _, acl := range iter.ACL {
|
|
||||||
// Determine whether the ACL applies to client. If it is
|
|
||||||
// a user ACL and the user id of the ACL matches client, we're good to go.
|
|
||||||
//
|
|
||||||
// If it's a group ACL, we have to parse and interpret the group string in the
|
|
||||||
// current context to determine membership. For that we use GroupMemberCheck.
|
|
||||||
matchUser := acl.IsUserACL() && acl.UserId == client.UserId()
|
|
||||||
matchGroup := GroupMemberCheck(channel, iter, acl.Group, client)
|
|
||||||
if matchUser || matchGroup {
|
|
||||||
if acl.Allow.IsSet(TraversePermission) {
|
|
||||||
traverse = true
|
|
||||||
}
|
|
||||||
if acl.Deny.IsSet(TraversePermission) {
|
|
||||||
traverse = false
|
|
||||||
}
|
|
||||||
if acl.Allow.IsSet(WritePermission) {
|
|
||||||
write = true
|
|
||||||
}
|
|
||||||
if acl.Deny.IsSet(WritePermission) {
|
|
||||||
write = false
|
|
||||||
}
|
|
||||||
if (channel == iter && acl.ApplyHere) || (channel != iter && acl.ApplySubs) {
|
|
||||||
granted |= acl.Allow
|
|
||||||
granted &= ^acl.Deny
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If traverse is not set and the user doesn't have write permissions
|
|
||||||
// on the channel, the user will not have any permissions.
|
|
||||||
// This is because -traverse removes all permissions, and +write grants
|
|
||||||
// all permissions.
|
|
||||||
if !traverse && !write {
|
|
||||||
granted = NonePermission
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the result
|
|
||||||
server.aclcache.StorePermission(client, channel, granted)
|
|
||||||
|
|
||||||
// The +write permission implies all permissions except for +speak and +whisper.
|
|
||||||
// This means that if the user has WritePermission, we should return true for all
|
|
||||||
// permissions exccept SpeakPermission and WhisperPermission.
|
|
||||||
if perm != SpeakPermission && perm != WhisperPermission {
|
|
||||||
return (granted & (perm | WritePermission)) != NonePermission
|
|
||||||
} else {
|
|
||||||
return (granted & perm) != NonePermission
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
16
channel.go
16
channel.go
|
|
@ -6,6 +6,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
)
|
)
|
||||||
|
|
||||||
// A Mumble channel
|
// A Mumble channel
|
||||||
|
|
@ -20,11 +21,7 @@ type Channel struct {
|
||||||
children map[int]*Channel
|
children map[int]*Channel
|
||||||
|
|
||||||
// ACL
|
// ACL
|
||||||
ACL []*ChannelACL
|
ACL acl.Context
|
||||||
InheritACL bool
|
|
||||||
|
|
||||||
// Groups
|
|
||||||
Groups map[string]*Group
|
|
||||||
|
|
||||||
// Links
|
// Links
|
||||||
Links map[int]*Channel
|
Links map[int]*Channel
|
||||||
|
|
@ -39,8 +36,7 @@ func NewChannel(id int, name string) (channel *Channel) {
|
||||||
channel.Name = name
|
channel.Name = name
|
||||||
channel.clients = make(map[uint32]*Client)
|
channel.clients = make(map[uint32]*Client)
|
||||||
channel.children = make(map[int]*Channel)
|
channel.children = make(map[int]*Channel)
|
||||||
channel.ACL = []*ChannelACL{}
|
channel.ACL.Groups = make(map[string]acl.Group)
|
||||||
channel.Groups = make(map[string]*Group)
|
|
||||||
channel.Links = make(map[int]*Channel)
|
channel.Links = make(map[int]*Channel)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -48,24 +44,26 @@ func NewChannel(id int, name string) (channel *Channel) {
|
||||||
// Add a child channel to a channel
|
// Add a child channel to a channel
|
||||||
func (channel *Channel) AddChild(child *Channel) {
|
func (channel *Channel) AddChild(child *Channel) {
|
||||||
child.parent = channel
|
child.parent = channel
|
||||||
|
child.ACL.Parent = &channel.ACL
|
||||||
channel.children[child.Id] = child
|
channel.children[child.Id] = child
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove a child channel from a parent
|
// Remove a child channel from a parent
|
||||||
func (channel *Channel) RemoveChild(child *Channel) {
|
func (channel *Channel) RemoveChild(child *Channel) {
|
||||||
child.parent = nil
|
child.parent = nil
|
||||||
|
child.ACL.Parent = nil
|
||||||
delete(channel.children, child.Id)
|
delete(channel.children, child.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add client
|
// Add client
|
||||||
func (channel *Channel) AddClient(client *Client) {
|
func (channel *Channel) AddClient(client *Client) {
|
||||||
channel.clients[client.Session] = client
|
channel.clients[client.Session()] = client
|
||||||
client.Channel = channel
|
client.Channel = channel
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove client
|
// Remove client
|
||||||
func (channel *Channel) RemoveClient(client *Client) {
|
func (channel *Channel) RemoveClient(client *Client) {
|
||||||
delete(channel.clients, client.Session)
|
delete(channel.clients, client.Session())
|
||||||
client.Channel = nil
|
client.Channel = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
33
client.go
33
client.go
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
"mumbleapp.com/grumble/pkg/cryptstate"
|
"mumbleapp.com/grumble/pkg/cryptstate"
|
||||||
"mumbleapp.com/grumble/pkg/mumbleproto"
|
"mumbleapp.com/grumble/pkg/mumbleproto"
|
||||||
"mumbleapp.com/grumble/pkg/packetdata"
|
"mumbleapp.com/grumble/pkg/packetdata"
|
||||||
|
|
@ -74,10 +75,10 @@ type Client struct {
|
||||||
|
|
||||||
// Personal
|
// Personal
|
||||||
Username string
|
Username string
|
||||||
Session uint32
|
session uint32
|
||||||
CertHash string
|
certHash string
|
||||||
Email string
|
Email string
|
||||||
Tokens []string
|
tokens []string
|
||||||
Channel *Channel
|
Channel *Channel
|
||||||
SelfMute bool
|
SelfMute bool
|
||||||
SelfDeaf bool
|
SelfDeaf bool
|
||||||
|
|
@ -97,7 +98,7 @@ func (client *Client) IsRegistered() bool {
|
||||||
|
|
||||||
// Does the client have a certificate?
|
// Does the client have a certificate?
|
||||||
func (client *Client) HasCertificate() bool {
|
func (client *Client) HasCertificate() bool {
|
||||||
return len(client.CertHash) > 0
|
return len(client.certHash) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is the client the SuperUser?
|
// Is the client the SuperUser?
|
||||||
|
|
@ -108,6 +109,22 @@ func (client *Client) IsSuperUser() bool {
|
||||||
return client.user.Id == 0
|
return client.user.Id == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) ACLContext() *acl.Context {
|
||||||
|
return &client.Channel.ACL
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) CertHash() string {
|
||||||
|
return client.certHash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) Session() uint32 {
|
||||||
|
return client.session
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) Tokens() []string {
|
||||||
|
return client.tokens
|
||||||
|
}
|
||||||
|
|
||||||
// Get the User ID of this client.
|
// Get the User ID of this client.
|
||||||
// Returns -1 if the client is not a registered user.
|
// Returns -1 if the client is not a registered user.
|
||||||
func (client *Client) UserId() int {
|
func (client *Client) UserId() int {
|
||||||
|
|
@ -252,7 +269,7 @@ func (c *Client) sendPermissionDeniedTypeUser(denyType mumbleproto.PermissionDen
|
||||||
Type: denyType.Enum(),
|
Type: denyType.Enum(),
|
||||||
}
|
}
|
||||||
if user != nil {
|
if user != nil {
|
||||||
pd.Session = proto.Uint32(uint32(user.Session))
|
pd.Session = proto.Uint32(uint32(user.Session()))
|
||||||
}
|
}
|
||||||
err := c.sendMessage(pd)
|
err := c.sendMessage(pd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -262,11 +279,11 @@ func (c *Client) sendPermissionDeniedTypeUser(denyType mumbleproto.PermissionDen
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send permission denied by who, what, where
|
// Send permission denied by who, what, where
|
||||||
func (c *Client) sendPermissionDenied(who *Client, where *Channel, what Permission) {
|
func (c *Client) sendPermissionDenied(who *Client, where *Channel, what acl.Permission) {
|
||||||
pd := &mumbleproto.PermissionDenied{
|
pd := &mumbleproto.PermissionDenied{
|
||||||
Permission: proto.Uint32(uint32(what)),
|
Permission: proto.Uint32(uint32(what)),
|
||||||
ChannelId: proto.Uint32(uint32(where.Id)),
|
ChannelId: proto.Uint32(uint32(where.Id)),
|
||||||
Session: proto.Uint32(who.Session),
|
Session: proto.Uint32(who.Session()),
|
||||||
Type: mumbleproto.PermissionDenied_Permission.Enum(),
|
Type: mumbleproto.PermissionDenied_Permission.Enum(),
|
||||||
}
|
}
|
||||||
err := c.sendMessage(pd)
|
err := c.sendMessage(pd)
|
||||||
|
|
@ -334,7 +351,7 @@ func (client *Client) udpRecvLoop() {
|
||||||
incoming.Skip(size & 0x1fff)
|
incoming.Skip(size & 0x1fff)
|
||||||
}
|
}
|
||||||
|
|
||||||
outgoing.PutUint32(client.Session)
|
outgoing.PutUint32(client.Session())
|
||||||
outgoing.PutBytes(buf[1 : 1+(len(buf)-1)])
|
outgoing.PutBytes(buf[1 : 1+(len(buf)-1)])
|
||||||
outbuf[0] = buf[0] & 0xe0 // strip target
|
outbuf[0] = buf[0] & 0xe0 // strip target
|
||||||
|
|
||||||
|
|
|
||||||
91
freeze.go
91
freeze.go
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
"mumbleapp.com/grumble/pkg/ban"
|
"mumbleapp.com/grumble/pkg/ban"
|
||||||
"mumbleapp.com/grumble/pkg/freezer"
|
"mumbleapp.com/grumble/pkg/freezer"
|
||||||
"mumbleapp.com/grumble/pkg/mumbleproto"
|
"mumbleapp.com/grumble/pkg/mumbleproto"
|
||||||
|
|
@ -170,12 +171,12 @@ func (channel *Channel) Freeze() (fc *freezer.Channel, err error) {
|
||||||
fc.ParentId = proto.Uint32(uint32(channel.parent.Id))
|
fc.ParentId = proto.Uint32(uint32(channel.parent.Id))
|
||||||
}
|
}
|
||||||
fc.Position = proto.Int64(int64(channel.Position))
|
fc.Position = proto.Int64(int64(channel.Position))
|
||||||
fc.InheritAcl = proto.Bool(channel.InheritACL)
|
fc.InheritAcl = proto.Bool(channel.ACL.InheritACL)
|
||||||
|
|
||||||
// Freeze the channel's ACLs
|
// Freeze the channel's ACLs
|
||||||
acls := []*freezer.ACL{}
|
acls := []*freezer.ACL{}
|
||||||
for _, acl := range channel.ACL {
|
for _, acl := range channel.ACL.ACLs {
|
||||||
facl, err := acl.Freeze()
|
facl, err := FreezeACL(acl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -185,8 +186,8 @@ func (channel *Channel) Freeze() (fc *freezer.Channel, err error) {
|
||||||
|
|
||||||
// Freeze the channel's groups
|
// Freeze the channel's groups
|
||||||
groups := []*freezer.Group{}
|
groups := []*freezer.Group{}
|
||||||
for _, grp := range channel.Groups {
|
for _, grp := range channel.ACL.Groups {
|
||||||
fgrp, err := grp.Freeze()
|
fgrp, err := FreezeGroup(grp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -217,7 +218,7 @@ func (c *Channel) Unfreeze(fc *freezer.Channel) {
|
||||||
c.Position = int(*fc.Position)
|
c.Position = int(*fc.Position)
|
||||||
}
|
}
|
||||||
if fc.InheritAcl != nil {
|
if fc.InheritAcl != nil {
|
||||||
c.InheritACL = *fc.InheritAcl
|
c.ACL.InheritACL = *fc.InheritAcl
|
||||||
}
|
}
|
||||||
if fc.DescriptionBlob != nil {
|
if fc.DescriptionBlob != nil {
|
||||||
c.DescriptionBlob = *fc.DescriptionBlob
|
c.DescriptionBlob = *fc.DescriptionBlob
|
||||||
|
|
@ -225,41 +226,41 @@ func (c *Channel) Unfreeze(fc *freezer.Channel) {
|
||||||
|
|
||||||
// Update ACLs
|
// Update ACLs
|
||||||
if fc.Acl != nil {
|
if fc.Acl != nil {
|
||||||
c.ACL = nil
|
c.ACL.ACLs = nil
|
||||||
for _, facl := range fc.Acl {
|
for _, facl := range fc.Acl {
|
||||||
acl := NewChannelACL(c)
|
aclEntry := acl.ACL{}
|
||||||
if facl.ApplyHere != nil {
|
if facl.ApplyHere != nil {
|
||||||
acl.ApplyHere = *facl.ApplyHere
|
aclEntry.ApplyHere = *facl.ApplyHere
|
||||||
}
|
}
|
||||||
if facl.ApplySubs != nil {
|
if facl.ApplySubs != nil {
|
||||||
acl.ApplySubs = *facl.ApplySubs
|
aclEntry.ApplySubs = *facl.ApplySubs
|
||||||
}
|
}
|
||||||
if facl.UserId != nil {
|
if facl.UserId != nil {
|
||||||
acl.UserId = int(*facl.UserId)
|
aclEntry.UserId = int(*facl.UserId)
|
||||||
} else {
|
} else {
|
||||||
acl.UserId = -1
|
aclEntry.UserId = -1
|
||||||
}
|
}
|
||||||
if facl.Group != nil {
|
if facl.Group != nil {
|
||||||
acl.Group = *facl.Group
|
aclEntry.Group = *facl.Group
|
||||||
}
|
}
|
||||||
if facl.Deny != nil {
|
if facl.Deny != nil {
|
||||||
acl.Deny = Permission(*facl.Deny)
|
aclEntry.Deny = acl.Permission(*facl.Deny)
|
||||||
}
|
}
|
||||||
if facl.Allow != nil {
|
if facl.Allow != nil {
|
||||||
acl.Allow = Permission(*facl.Allow)
|
aclEntry.Allow = acl.Permission(*facl.Allow)
|
||||||
}
|
}
|
||||||
c.ACL = append(c.ACL, acl)
|
c.ACL.ACLs = append(c.ACL.ACLs, aclEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update groups
|
// Update groups
|
||||||
if fc.Groups != nil {
|
if fc.Groups != nil {
|
||||||
c.Groups = make(map[string]*Group)
|
c.ACL.Groups = make(map[string]acl.Group)
|
||||||
for _, fgrp := range fc.Groups {
|
for _, fgrp := range fc.Groups {
|
||||||
if fgrp.Name == nil {
|
if fgrp.Name == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
g := NewGroup(c, *fgrp.Name)
|
g := acl.Group{}
|
||||||
if fgrp.Inherit != nil {
|
if fgrp.Inherit != nil {
|
||||||
g.Inherit = *fgrp.Inherit
|
g.Inherit = *fgrp.Inherit
|
||||||
}
|
}
|
||||||
|
|
@ -272,7 +273,7 @@ func (c *Channel) Unfreeze(fc *freezer.Channel) {
|
||||||
for _, uid := range fgrp.Remove {
|
for _, uid := range fgrp.Remove {
|
||||||
g.Remove[int(uid)] = true
|
g.Remove[int(uid)] = true
|
||||||
}
|
}
|
||||||
c.Groups[g.Name] = g
|
c.ACL.Groups[g.Name] = g
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -331,40 +332,34 @@ func (u *User) Unfreeze(fu *freezer.User) {
|
||||||
|
|
||||||
// Freeze a ChannelACL into it a flattened protobuf-based structure
|
// Freeze a ChannelACL into it a flattened protobuf-based structure
|
||||||
// ready to be persisted to disk.
|
// ready to be persisted to disk.
|
||||||
func (acl *ChannelACL) Freeze() (facl *freezer.ACL, err error) {
|
func FreezeACL(aclEntry acl.ACL) (*freezer.ACL, error) {
|
||||||
facl = new(freezer.ACL)
|
frozenAcl := &freezer.ACL{}
|
||||||
|
if aclEntry.UserId != -1 {
|
||||||
if acl.UserId != -1 {
|
frozenAcl.UserId = proto.Uint32(uint32(aclEntry.UserId))
|
||||||
facl.UserId = proto.Uint32(uint32(acl.UserId))
|
|
||||||
} else {
|
} else {
|
||||||
facl.Group = proto.String(acl.Group)
|
frozenAcl.Group = proto.String(aclEntry.Group)
|
||||||
}
|
}
|
||||||
facl.ApplyHere = proto.Bool(acl.ApplyHere)
|
frozenAcl.ApplyHere = proto.Bool(aclEntry.ApplyHere)
|
||||||
facl.ApplySubs = proto.Bool(acl.ApplySubs)
|
frozenAcl.ApplySubs = proto.Bool(aclEntry.ApplySubs)
|
||||||
facl.Allow = proto.Uint32(uint32(acl.Allow))
|
frozenAcl.Allow = proto.Uint32(uint32(aclEntry.Allow))
|
||||||
facl.Deny = proto.Uint32(uint32(acl.Deny))
|
frozenAcl.Deny = proto.Uint32(uint32(aclEntry.Deny))
|
||||||
|
return frozenAcl, nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Freeze a Group into a flattened protobuf-based structure
|
// Freeze a Group into a flattened protobuf-based structure
|
||||||
// ready to be persisted to disk.
|
// ready to be persisted to disk.
|
||||||
func (group *Group) Freeze() (fgrp *freezer.Group, err error) {
|
func FreezeGroup(group acl.Group) (*freezer.Group, error) {
|
||||||
fgrp = new(freezer.Group)
|
frozenGroup := &freezer.Group{}
|
||||||
|
frozenGroup.Name = proto.String(group.Name)
|
||||||
fgrp.Name = proto.String(group.Name)
|
frozenGroup.Inherit = proto.Bool(group.Inherit)
|
||||||
fgrp.Inherit = proto.Bool(group.Inherit)
|
frozenGroup.Inheritable = proto.Bool(group.Inheritable)
|
||||||
fgrp.Inheritable = proto.Bool(group.Inheritable)
|
|
||||||
|
|
||||||
for _, id := range group.AddUsers() {
|
for _, id := range group.AddUsers() {
|
||||||
fgrp.Add = append(fgrp.Add, uint32(id))
|
frozenGroup.Add = append(frozenGroup.Add, uint32(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, id := range group.RemoveUsers() {
|
for _, id := range group.RemoveUsers() {
|
||||||
fgrp.Remove = append(fgrp.Remove, uint32(id))
|
frozenGroup.Remove = append(frozenGroup.Remove, uint32(id))
|
||||||
}
|
}
|
||||||
|
return frozenGroup, nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new server from its on-disk representation.
|
// Create a new server from its on-disk representation.
|
||||||
|
|
@ -788,11 +783,11 @@ func (server *Server) UpdateFrozenChannelACLs(channel *Channel) {
|
||||||
fc := &freezer.Channel{}
|
fc := &freezer.Channel{}
|
||||||
|
|
||||||
fc.Id = proto.Uint32(uint32(channel.Id))
|
fc.Id = proto.Uint32(uint32(channel.Id))
|
||||||
fc.InheritAcl = proto.Bool(channel.InheritACL)
|
fc.InheritAcl = proto.Bool(channel.ACL.InheritACL)
|
||||||
|
|
||||||
acls := []*freezer.ACL{}
|
acls := []*freezer.ACL{}
|
||||||
for _, acl := range channel.ACL {
|
for _, aclEntry := range channel.ACL.ACLs {
|
||||||
facl, err := acl.Freeze()
|
facl, err := FreezeACL(aclEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -801,8 +796,8 @@ func (server *Server) UpdateFrozenChannelACLs(channel *Channel) {
|
||||||
fc.Acl = acls
|
fc.Acl = acls
|
||||||
|
|
||||||
groups := []*freezer.Group{}
|
groups := []*freezer.Group{}
|
||||||
for _, grp := range channel.Groups {
|
for _, grp := range channel.ACL.Groups {
|
||||||
fgrp, err := grp.Freeze()
|
fgrp, err := FreezeGroup(grp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
244
message.go
244
message.go
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"crypto/aes"
|
"crypto/aes"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
"mumbleapp.com/grumble/pkg/ban"
|
"mumbleapp.com/grumble/pkg/ban"
|
||||||
"mumbleapp.com/grumble/pkg/freezer"
|
"mumbleapp.com/grumble/pkg/freezer"
|
||||||
"mumbleapp.com/grumble/pkg/mumbleproto"
|
"mumbleapp.com/grumble/pkg/mumbleproto"
|
||||||
|
|
@ -129,8 +130,8 @@ func (server *Server) handleChannelRemoveMessage(client *Client, msg *Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !server.HasPermission(client, channel, WritePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -225,13 +226,13 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the client has permission to create the channel in parent.
|
// Check whether the client has permission to create the channel in parent.
|
||||||
perm := Permission(NonePermission)
|
perm := acl.Permission(acl.NonePermission)
|
||||||
if *chanstate.Temporary {
|
if *chanstate.Temporary {
|
||||||
perm = Permission(TempChannelPermission)
|
perm = acl.Permission(acl.TempChannelPermission)
|
||||||
} else {
|
} else {
|
||||||
perm = Permission(MakeChannelPermission)
|
perm = acl.Permission(acl.MakeChannelPermission)
|
||||||
}
|
}
|
||||||
if !server.HasPermission(client, parent, perm) {
|
if !acl.HasPermission(&parent.ACL, client, perm) {
|
||||||
client.sendPermissionDenied(client, parent, perm)
|
client.sendPermissionDenied(client, parent, perm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -265,26 +266,26 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
// Add the creator to the channel's admin group
|
// Add the creator to the channel's admin group
|
||||||
if client.IsRegistered() {
|
if client.IsRegistered() {
|
||||||
grp := NewGroup(channel, "admin")
|
grp := acl.EmptyGroupWithName("admin")
|
||||||
grp.Add[client.UserId()] = true
|
grp.Add[client.UserId()] = true
|
||||||
channel.Groups["admin"] = grp
|
channel.ACL.Groups["admin"] = grp
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the client wouldn't have WritePermission in the just-created channel,
|
// If the client wouldn't have WritePermission in the just-created channel,
|
||||||
// add a +write ACL for the user's hash.
|
// add a +write ACL for the user's hash.
|
||||||
if !server.HasPermission(client, channel, WritePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) {
|
||||||
acl := NewChannelACL(channel)
|
aclEntry := acl.ACL{}
|
||||||
acl.ApplyHere = true
|
aclEntry.ApplyHere = true
|
||||||
acl.ApplySubs = true
|
aclEntry.ApplySubs = true
|
||||||
if client.IsRegistered() {
|
if client.IsRegistered() {
|
||||||
acl.UserId = client.UserId()
|
aclEntry.UserId = client.UserId()
|
||||||
} else {
|
} else {
|
||||||
acl.Group = "$" + client.CertHash
|
aclEntry.Group = "$" + client.CertHash()
|
||||||
}
|
}
|
||||||
acl.Deny = Permission(NonePermission)
|
aclEntry.Deny = acl.Permission(acl.NonePermission)
|
||||||
acl.Allow = Permission(WritePermission | TraversePermission)
|
aclEntry.Allow = acl.Permission(acl.WritePermission | acl.TraversePermission)
|
||||||
|
|
||||||
channel.ACL = append(channel.ACL, acl)
|
channel.ACL.ACLs = append(channel.ACL.ACLs, aclEntry)
|
||||||
|
|
||||||
server.ClearCaches()
|
server.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
@ -308,7 +309,7 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
// If it's a temporary channel, move the creator in there.
|
// If it's a temporary channel, move the creator in there.
|
||||||
if channel.IsTemporary() {
|
if channel.IsTemporary() {
|
||||||
userstate := &mumbleproto.UserState{}
|
userstate := &mumbleproto.UserState{}
|
||||||
userstate.Session = proto.Uint32(client.Session)
|
userstate.Session = proto.Uint32(client.Session())
|
||||||
userstate.ChannelId = proto.Uint32(uint32(channel.Id))
|
userstate.ChannelId = proto.Uint32(uint32(channel.Id))
|
||||||
server.userEnterChannel(client, channel, userstate)
|
server.userEnterChannel(client, channel, userstate)
|
||||||
server.broadcastProtoMessage(userstate)
|
server.broadcastProtoMessage(userstate)
|
||||||
|
|
@ -321,24 +322,24 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
if chanstate.Name != nil {
|
if chanstate.Name != nil {
|
||||||
// The client can only rename the channel if it has WritePermission in the channel.
|
// The client can only rename the channel if it has WritePermission in the channel.
|
||||||
// Also, clients cannot change the name of the root channel.
|
// Also, clients cannot change the name of the root channel.
|
||||||
if !server.HasPermission(client, channel, WritePermission) || channel.Id == 0 {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) || channel.Id == 0 {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Description change
|
// Description change
|
||||||
if chanstate.Description != nil {
|
if chanstate.Description != nil {
|
||||||
if !server.HasPermission(client, channel, WritePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position change
|
// Position change
|
||||||
if chanstate.Position != nil {
|
if chanstate.Position != nil {
|
||||||
if !server.HasPermission(client, channel, WritePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -367,14 +368,14 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// To move a channel, the user must have WritePermission in the channel
|
// To move a channel, the user must have WritePermission in the channel
|
||||||
if !server.HasPermission(client, channel, WritePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// And the user must also have MakeChannel permission in the new parent
|
// And the user must also have MakeChannel permission in the new parent
|
||||||
if !server.HasPermission(client, parent, MakeChannelPermission) {
|
if !acl.HasPermission(&parent.ACL, client, acl.MakeChannelPermission) {
|
||||||
client.sendPermissionDenied(client, parent, MakeChannelPermission)
|
client.sendPermissionDenied(client, parent, acl.MakeChannelPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -392,8 +393,8 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
linkremove := []*Channel{}
|
linkremove := []*Channel{}
|
||||||
if len(chanstate.LinksAdd) > 0 || len(chanstate.LinksRemove) > 0 {
|
if len(chanstate.LinksAdd) > 0 || len(chanstate.LinksRemove) > 0 {
|
||||||
// Client must have permission to link
|
// Client must have permission to link
|
||||||
if !server.HasPermission(client, channel, LinkChannelPermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.LinkChannelPermission) {
|
||||||
client.sendPermissionDenied(client, channel, LinkChannelPermission)
|
client.sendPermissionDenied(client, channel, acl.LinkChannelPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Add any valid channels to linkremove slice
|
// Add any valid channels to linkremove slice
|
||||||
|
|
@ -405,8 +406,8 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
|
||||||
// Add any valid channels to linkadd slice
|
// Add any valid channels to linkadd slice
|
||||||
for _, cid := range chanstate.LinksAdd {
|
for _, cid := range chanstate.LinksAdd {
|
||||||
if iter, ok := server.Channels[int(cid)]; ok {
|
if iter, ok := server.Channels[int(cid)]; ok {
|
||||||
if !server.HasPermission(client, iter, LinkChannelPermission) {
|
if !acl.HasPermission(&iter.ACL, client, acl.LinkChannelPermission) {
|
||||||
client.sendPermissionDenied(client, iter, LinkChannelPermission)
|
client.sendPermissionDenied(client, iter, acl.LinkChannelPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
linkadd = append(linkadd, iter)
|
linkadd = append(linkadd, iter)
|
||||||
|
|
@ -500,12 +501,13 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check client's permissions
|
// Check client's permissions
|
||||||
perm := Permission(KickPermission)
|
perm := acl.Permission(acl.KickPermission)
|
||||||
if isBan {
|
if isBan {
|
||||||
perm = Permission(BanPermission)
|
perm = acl.Permission(acl.BanPermission)
|
||||||
}
|
}
|
||||||
if removeClient.IsSuperUser() || !server.HasPermission(client, server.RootChannel(), perm) {
|
rootChan := server.RootChannel()
|
||||||
client.sendPermissionDenied(client, server.RootChannel(), perm)
|
if removeClient.IsSuperUser() || !acl.HasPermission(&rootChan.ACL, client, perm) {
|
||||||
|
client.sendPermissionDenied(client, rootChan, perm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,7 +519,7 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
|
||||||
ban.Reason = *userremove.Reason
|
ban.Reason = *userremove.Reason
|
||||||
}
|
}
|
||||||
ban.Username = removeClient.ShownName()
|
ban.Username = removeClient.ShownName()
|
||||||
ban.CertHash = removeClient.CertHash
|
ban.CertHash = removeClient.CertHash()
|
||||||
ban.Start = time.Now().Unix()
|
ban.Start = time.Now().Unix()
|
||||||
ban.Duration = 0
|
ban.Duration = 0
|
||||||
|
|
||||||
|
|
@ -527,16 +529,16 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
|
||||||
server.banlock.Unlock()
|
server.banlock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
userremove.Actor = proto.Uint32(uint32(client.Session))
|
userremove.Actor = proto.Uint32(uint32(client.Session()))
|
||||||
if err = server.broadcastProtoMessage(userremove); err != nil {
|
if err = server.broadcastProtoMessage(userremove); err != nil {
|
||||||
server.Panicf("Unable to broadcast UserRemove message")
|
server.Panicf("Unable to broadcast UserRemove message")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if isBan {
|
if isBan {
|
||||||
client.Printf("Kick-banned %v (%v)", removeClient.ShownName(), removeClient.Session)
|
client.Printf("Kick-banned %v (%v)", removeClient.ShownName(), removeClient.Session())
|
||||||
} else {
|
} else {
|
||||||
client.Printf("Kicked %v (%v)", removeClient.ShownName(), removeClient.Session)
|
client.Printf("Kicked %v (%v)", removeClient.ShownName(), removeClient.Session())
|
||||||
}
|
}
|
||||||
|
|
||||||
removeClient.ForceDisconnect()
|
removeClient.ForceDisconnect()
|
||||||
|
|
@ -551,7 +553,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
actor, ok := server.clients[client.Session]
|
actor, ok := server.clients[client.Session()]
|
||||||
if !ok {
|
if !ok {
|
||||||
server.Panic("Client not found in server's client map.")
|
server.Panic("Client not found in server's client map.")
|
||||||
return
|
return
|
||||||
|
|
@ -565,8 +567,8 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
userstate.Session = proto.Uint32(target.Session)
|
userstate.Session = proto.Uint32(target.Session())
|
||||||
userstate.Actor = proto.Uint32(actor.Session)
|
userstate.Actor = proto.Uint32(actor.Session())
|
||||||
|
|
||||||
// Does it have a channel ID?
|
// Does it have a channel ID?
|
||||||
if userstate.ChannelId != nil {
|
if userstate.ChannelId != nil {
|
||||||
|
|
@ -578,15 +580,15 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
// If the user and the actor aren't the same, check whether the actor has MovePermission on
|
// If the user and the actor aren't the same, check whether the actor has MovePermission on
|
||||||
// the user's curent channel.
|
// the user's curent channel.
|
||||||
if actor != target && !server.HasPermission(actor, target.Channel, MovePermission) {
|
if actor != target && !acl.HasPermission(&target.Channel.ACL, actor, acl.MovePermission) {
|
||||||
client.sendPermissionDenied(actor, target.Channel, MovePermission)
|
client.sendPermissionDenied(actor, target.Channel, acl.MovePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the actor has MovePermission on dstChan. Check whether user has EnterPermission
|
// Check whether the actor has MovePermission on dstChan. Check whether user has EnterPermission
|
||||||
// on dstChan.
|
// on dstChan.
|
||||||
if !server.HasPermission(actor, dstChan, MovePermission) && !server.HasPermission(target, dstChan, EnterPermission) {
|
if !acl.HasPermission(&dstChan.ACL, actor, acl.MovePermission) && !acl.HasPermission(&dstChan.ACL, target, acl.EnterPermission) {
|
||||||
client.sendPermissionDenied(target, dstChan, EnterPermission)
|
client.sendPermissionDenied(target, dstChan, acl.EnterPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -606,14 +608,14 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the actor has 'mutedeafen' permission on user's channel.
|
// Check whether the actor has 'mutedeafen' permission on user's channel.
|
||||||
if !server.HasPermission(actor, target.Channel, MuteDeafenPermission) {
|
if !acl.HasPermission(&target.Channel.ACL, actor, acl.MuteDeafenPermission) {
|
||||||
client.sendPermissionDenied(actor, target.Channel, MuteDeafenPermission)
|
client.sendPermissionDenied(actor, target.Channel, acl.MuteDeafenPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this was a suppress operation. Only the server can suppress users.
|
// Check if this was a suppress operation. Only the server can suppress users.
|
||||||
if userstate.Suppress != nil {
|
if userstate.Suppress != nil {
|
||||||
client.sendPermissionDenied(actor, target.Channel, MuteDeafenPermission)
|
client.sendPermissionDenied(actor, target.Channel, acl.MuteDeafenPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -626,8 +628,9 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
if target != actor {
|
if target != actor {
|
||||||
// Check if actor has 'move' permissions on the root channel. It is needed
|
// Check if actor has 'move' permissions on the root channel. It is needed
|
||||||
// to clear another user's comment.
|
// to clear another user's comment.
|
||||||
if !server.HasPermission(actor, server.RootChannel(), MovePermission) {
|
rootChan := server.RootChannel()
|
||||||
client.sendPermissionDenied(actor, server.RootChannel(), MovePermission)
|
if !acl.HasPermission(&rootChan.ACL, actor, acl.MovePermission) {
|
||||||
|
client.sendPermissionDenied(actor, rootChan, acl.MovePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -660,17 +663,18 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
|
||||||
if userstate.UserId != nil {
|
if userstate.UserId != nil {
|
||||||
// If user == actor, check for SelfRegisterPermission on root channel.
|
// If user == actor, check for SelfRegisterPermission on root channel.
|
||||||
// If user != actor, check for RegisterPermission permission on root channel.
|
// If user != actor, check for RegisterPermission permission on root channel.
|
||||||
perm := Permission(RegisterPermission)
|
perm := acl.Permission(acl.RegisterPermission)
|
||||||
if actor == target {
|
if actor == target {
|
||||||
perm = Permission(SelfRegisterPermission)
|
perm = acl.Permission(acl.SelfRegisterPermission)
|
||||||
}
|
}
|
||||||
|
|
||||||
if target.IsRegistered() || !server.HasPermission(actor, server.RootChannel(), perm) {
|
rootChan := server.RootChannel()
|
||||||
client.sendPermissionDenied(actor, server.RootChannel(), perm)
|
if target.IsRegistered() || !acl.HasPermission(&rootChan.ACL, actor, perm) {
|
||||||
|
client.sendPermissionDenied(actor, rootChan, perm)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(target.CertHash) == 0 {
|
if !target.HasCertificate() {
|
||||||
client.sendPermissionDeniedTypeUser(mumbleproto.PermissionDenied_MissingCertificate, target)
|
client.sendPermissionDeniedTypeUser(mumbleproto.PermissionDenied_MissingCertificate, target)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -890,8 +894,9 @@ func (server *Server) handleBanListMessage(client *Client, msg *Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !server.HasPermission(client, server.RootChannel(), BanPermission) {
|
rootChan := server.RootChannel()
|
||||||
client.sendPermissionDenied(client, server.RootChannel(), BanPermission)
|
if !acl.HasPermission(&rootChan.ACL, client, acl.BanPermission) {
|
||||||
|
client.sendPermissionDenied(client, rootChan, acl.BanPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -974,12 +979,12 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
|
||||||
// Tree
|
// Tree
|
||||||
for _, chanid := range txtmsg.TreeId {
|
for _, chanid := range txtmsg.TreeId {
|
||||||
if channel, ok := server.Channels[int(chanid)]; ok {
|
if channel, ok := server.Channels[int(chanid)]; ok {
|
||||||
if !server.HasPermission(client, channel, TextMessagePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.TextMessagePermission) {
|
||||||
client.sendPermissionDenied(client, channel, TextMessagePermission)
|
client.sendPermissionDenied(client, channel, acl.TextMessagePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, target := range channel.clients {
|
for _, target := range channel.clients {
|
||||||
clients[target.Session] = target
|
clients[target.Session()] = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -987,12 +992,12 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
|
||||||
// Direct-to-channel
|
// Direct-to-channel
|
||||||
for _, chanid := range txtmsg.ChannelId {
|
for _, chanid := range txtmsg.ChannelId {
|
||||||
if channel, ok := server.Channels[int(chanid)]; ok {
|
if channel, ok := server.Channels[int(chanid)]; ok {
|
||||||
if !server.HasPermission(client, channel, TextMessagePermission) {
|
if !acl.HasPermission(&channel.ACL, client, acl.TextMessagePermission) {
|
||||||
client.sendPermissionDenied(client, channel, TextMessagePermission)
|
client.sendPermissionDenied(client, channel, acl.TextMessagePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, target := range channel.clients {
|
for _, target := range channel.clients {
|
||||||
clients[target.Session] = target
|
clients[target.Session()] = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1000,8 +1005,8 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
|
||||||
// Direct-to-clients
|
// Direct-to-clients
|
||||||
for _, session := range txtmsg.Session {
|
for _, session := range txtmsg.Session {
|
||||||
if target, ok := server.clients[session]; ok {
|
if target, ok := server.clients[session]; ok {
|
||||||
if !server.HasPermission(client, target.Channel, TextMessagePermission) {
|
if !acl.HasPermission(&target.Channel.ACL, client, acl.TextMessagePermission) {
|
||||||
client.sendPermissionDenied(client, target.Channel, TextMessagePermission)
|
client.sendPermissionDenied(client, target.Channel, acl.TextMessagePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clients[session] = target
|
clients[session] = target
|
||||||
|
|
@ -1009,11 +1014,11 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove ourselves
|
// Remove ourselves
|
||||||
delete(clients, client.Session)
|
delete(clients, client.Session())
|
||||||
|
|
||||||
for _, target := range clients {
|
for _, target := range clients {
|
||||||
target.sendMessage(&mumbleproto.TextMessage{
|
target.sendMessage(&mumbleproto.TextMessage{
|
||||||
Actor: proto.Uint32(client.Session),
|
Actor: proto.Uint32(client.Session()),
|
||||||
Message: txtmsg.Message,
|
Message: txtmsg.Message,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -1021,22 +1026,22 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
// ACL set/query
|
// ACL set/query
|
||||||
func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
acl := &mumbleproto.ACL{}
|
pacl := &mumbleproto.ACL{}
|
||||||
err := proto.Unmarshal(msg.buf, acl)
|
err := proto.Unmarshal(msg.buf, pacl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.Panic(err)
|
client.Panic(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look up the channel this ACL message operates on.
|
// Look up the channel this ACL message operates on.
|
||||||
channel, ok := server.Channels[int(*acl.ChannelId)]
|
channel, ok := server.Channels[int(*pacl.ChannelId)]
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does the user have permission to update or look at ACLs?
|
// Does the user have permission to update or look at ACLs?
|
||||||
if !server.HasPermission(client, channel, WritePermission) && !(channel.parent != nil && server.HasPermission(client, channel.parent, WritePermission)) {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && !(channel.parent != nil && acl.HasPermission(&channel.parent.ACL, client, acl.WritePermission)) {
|
||||||
client.sendPermissionDenied(client, channel, WritePermission)
|
client.sendPermissionDenied(client, channel, acl.WritePermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1047,14 +1052,14 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
users := map[int]bool{}
|
users := map[int]bool{}
|
||||||
|
|
||||||
// Query the current ACL state for the channel
|
// Query the current ACL state for the channel
|
||||||
if acl.Query != nil && *acl.Query != false {
|
if pacl.Query != nil && *pacl.Query != false {
|
||||||
reply.InheritAcls = proto.Bool(channel.InheritACL)
|
reply.InheritAcls = proto.Bool(channel.ACL.InheritACL)
|
||||||
// Walk the channel tree to get all relevant channels.
|
// Walk the channel tree to get all relevant channels.
|
||||||
// (Stop if we reach a channel that doesn't have the InheritACL flag set)
|
// (Stop if we reach a channel that doesn't have the InheritACL flag set)
|
||||||
iter := channel
|
iter := channel
|
||||||
for iter != nil {
|
for iter != nil {
|
||||||
channels = append([]*Channel{iter}, channels...)
|
channels = append([]*Channel{iter}, channels...)
|
||||||
if iter == channel || iter.InheritACL {
|
if iter == channel || iter.ACL.InheritACL {
|
||||||
iter = iter.parent
|
iter = iter.parent
|
||||||
} else {
|
} else {
|
||||||
iter = nil
|
iter = nil
|
||||||
|
|
@ -1065,7 +1070,7 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
// in our channel list.
|
// in our channel list.
|
||||||
reply.Acls = []*mumbleproto.ACL_ChanACL{}
|
reply.Acls = []*mumbleproto.ACL_ChanACL{}
|
||||||
for _, iter := range channels {
|
for _, iter := range channels {
|
||||||
for _, chanacl := range iter.ACL {
|
for _, chanacl := range iter.ACL.ACLs {
|
||||||
if iter == channel || chanacl.ApplySubs {
|
if iter == channel || chanacl.ApplySubs {
|
||||||
mpacl := &mumbleproto.ACL_ChanACL{}
|
mpacl := &mumbleproto.ACL_ChanACL{}
|
||||||
mpacl.Inherited = proto.Bool(iter != channel)
|
mpacl.Inherited = proto.Bool(iter != channel)
|
||||||
|
|
@ -1085,40 +1090,43 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
parent := channel.parent
|
parent := channel.parent
|
||||||
allnames := channel.GroupNames()
|
allnames := channel.ACL.GroupNames()
|
||||||
|
|
||||||
// Construct the protobuf ChanGroups that we send back to the client.
|
// Construct the protobuf ChanGroups that we send back to the client.
|
||||||
// Also constructs a usermap that is a set user ids from the channel's groups.
|
// Also constructs a usermap that is a set user ids from the channel's groups.
|
||||||
reply.Groups = []*mumbleproto.ACL_ChanGroup{}
|
reply.Groups = []*mumbleproto.ACL_ChanGroup{}
|
||||||
for name, _ := range allnames {
|
for _, name := range allnames {
|
||||||
var (
|
var (
|
||||||
group *Group
|
group acl.Group
|
||||||
pgroup *Group
|
hasgroup bool
|
||||||
|
pgroup acl.Group
|
||||||
|
haspgroup bool
|
||||||
)
|
)
|
||||||
group = channel.Groups[name]
|
|
||||||
|
group, hasgroup = channel.ACL.Groups[name]
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
pgroup = parent.Groups[name]
|
pgroup, haspgroup = parent.ACL.Groups[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
mpgroup := &mumbleproto.ACL_ChanGroup{}
|
mpgroup := &mumbleproto.ACL_ChanGroup{}
|
||||||
mpgroup.Name = proto.String(name)
|
mpgroup.Name = proto.String(name)
|
||||||
|
|
||||||
mpgroup.Inherit = proto.Bool(true)
|
mpgroup.Inherit = proto.Bool(true)
|
||||||
if group != nil {
|
if hasgroup {
|
||||||
mpgroup.Inherit = proto.Bool(group.Inherit)
|
mpgroup.Inherit = proto.Bool(group.Inherit)
|
||||||
}
|
}
|
||||||
|
|
||||||
mpgroup.Inheritable = proto.Bool(true)
|
mpgroup.Inheritable = proto.Bool(true)
|
||||||
if group != nil {
|
if hasgroup {
|
||||||
mpgroup.Inheritable = proto.Bool(group.Inheritable)
|
mpgroup.Inheritable = proto.Bool(group.Inheritable)
|
||||||
}
|
}
|
||||||
|
|
||||||
mpgroup.Inherited = proto.Bool(pgroup != nil && pgroup.Inheritable)
|
mpgroup.Inherited = proto.Bool(haspgroup && pgroup.Inheritable)
|
||||||
|
|
||||||
// Add the set of user ids that this group affects to the user map.
|
// Add the set of user ids that this group affects to the user map.
|
||||||
// This is used later on in this function to send the client a QueryUsers
|
// This is used later on in this function to send the client a QueryUsers
|
||||||
// message that maps user ids to usernames.
|
// message that maps user ids to usernames.
|
||||||
if group != nil {
|
if hasgroup {
|
||||||
toadd := map[int]bool{}
|
toadd := map[int]bool{}
|
||||||
for uid, _ := range group.Add {
|
for uid, _ := range group.Add {
|
||||||
users[uid] = true
|
users[uid] = true
|
||||||
|
|
@ -1132,8 +1140,8 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
mpgroup.Add = append(mpgroup.Add, uint32(uid))
|
mpgroup.Add = append(mpgroup.Add, uint32(uid))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pgroup != nil {
|
if haspgroup {
|
||||||
for uid, _ := range pgroup.Members() {
|
for uid, _ := range pgroup.MembersInContext(&parent.ACL) {
|
||||||
users[uid] = true
|
users[uid] = true
|
||||||
mpgroup.InheritedMembers = append(mpgroup.InheritedMembers, uint32(uid))
|
mpgroup.InheritedMembers = append(mpgroup.InheritedMembers, uint32(uid))
|
||||||
}
|
}
|
||||||
|
|
@ -1167,18 +1175,18 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
|
|
||||||
// Get old temporary members
|
// Get old temporary members
|
||||||
oldtmp := map[string]map[int]bool{}
|
oldtmp := map[string]map[int]bool{}
|
||||||
for name, grp := range channel.Groups {
|
for name, grp := range channel.ACL.Groups {
|
||||||
oldtmp[name] = grp.Temporary
|
oldtmp[name] = grp.Temporary
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear current ACLs and groups
|
// Clear current ACLs and groups
|
||||||
channel.ACL = []*ChannelACL{}
|
channel.ACL.ACLs = []acl.ACL{}
|
||||||
channel.Groups = map[string]*Group{}
|
channel.ACL.Groups = map[string]acl.Group{}
|
||||||
|
|
||||||
// Add the received groups to the channel.
|
// Add the received groups to the channel.
|
||||||
channel.InheritACL = *acl.InheritAcls
|
channel.ACL.InheritACL = *pacl.InheritAcls
|
||||||
for _, pbgrp := range acl.Groups {
|
for _, pbgrp := range pacl.Groups {
|
||||||
changroup := NewGroup(channel, *pbgrp.Name)
|
changroup := acl.EmptyGroupWithName(*pbgrp.Name)
|
||||||
|
|
||||||
changroup.Inherit = *pbgrp.Inherit
|
changroup.Inherit = *pbgrp.Inherit
|
||||||
changroup.Inheritable = *pbgrp.Inheritable
|
changroup.Inheritable = *pbgrp.Inheritable
|
||||||
|
|
@ -1192,12 +1200,11 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
changroup.Temporary = temp
|
changroup.Temporary = temp
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.Groups[changroup.Name] = changroup
|
channel.ACL.Groups[changroup.Name] = changroup
|
||||||
}
|
}
|
||||||
// Add the received ACLs to the channel.
|
// Add the received ACLs to the channel.
|
||||||
for _, pbacl := range acl.Acls {
|
for _, pbacl := range pacl.Acls {
|
||||||
chanacl := NewChannelACL(channel)
|
chanacl := acl.ACL{}
|
||||||
|
|
||||||
chanacl.ApplyHere = *pbacl.ApplyHere
|
chanacl.ApplyHere = *pbacl.ApplyHere
|
||||||
chanacl.ApplySubs = *pbacl.ApplySubs
|
chanacl.ApplySubs = *pbacl.ApplySubs
|
||||||
if pbacl.UserId != nil {
|
if pbacl.UserId != nil {
|
||||||
|
|
@ -1205,30 +1212,29 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
|
||||||
} else {
|
} else {
|
||||||
chanacl.Group = *pbacl.Group
|
chanacl.Group = *pbacl.Group
|
||||||
}
|
}
|
||||||
chanacl.Deny = Permission(*pbacl.Deny & AllPermissions)
|
chanacl.Deny = acl.Permission(*pbacl.Deny & acl.AllPermissions)
|
||||||
chanacl.Allow = Permission(*pbacl.Grant & AllPermissions)
|
chanacl.Allow = acl.Permission(*pbacl.Grant & acl.AllPermissions)
|
||||||
|
|
||||||
channel.ACL = append(channel.ACL, chanacl)
|
channel.ACL.ACLs = append(channel.ACL.ACLs, chanacl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear the Server's caches
|
// Clear the Server's caches
|
||||||
server.ClearCaches()
|
server.ClearCaches()
|
||||||
|
|
||||||
// Regular user?
|
// Regular user?
|
||||||
if !server.HasPermission(client, channel, WritePermission) && client.IsRegistered() || client.HasCertificate() {
|
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && client.IsRegistered() || client.HasCertificate() {
|
||||||
chanacl := NewChannelACL(channel)
|
chanacl := acl.ACL{}
|
||||||
|
|
||||||
chanacl.ApplyHere = true
|
chanacl.ApplyHere = true
|
||||||
chanacl.ApplySubs = false
|
chanacl.ApplySubs = false
|
||||||
if client.IsRegistered() {
|
if client.IsRegistered() {
|
||||||
chanacl.UserId = client.UserId()
|
chanacl.UserId = client.UserId()
|
||||||
} else if client.HasCertificate() {
|
} else if client.HasCertificate() {
|
||||||
chanacl.Group = "$" + client.CertHash
|
chanacl.Group = "$" + client.CertHash()
|
||||||
}
|
}
|
||||||
chanacl.Deny = Permission(NonePermission)
|
chanacl.Deny = acl.Permission(acl.NonePermission)
|
||||||
chanacl.Allow = Permission(WritePermission | TraversePermission)
|
chanacl.Allow = acl.Permission(acl.WritePermission | acl.TraversePermission)
|
||||||
|
|
||||||
channel.ACL = append(channel.ACL, chanacl)
|
channel.ACL.ACLs = append(channel.ACL.ACLs, chanacl)
|
||||||
|
|
||||||
server.ClearCaches()
|
server.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
@ -1299,14 +1305,15 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
// Otherwise, only send extended UserStats for people with +register permissions
|
// Otherwise, only send extended UserStats for people with +register permissions
|
||||||
// on the root channel.
|
// on the root channel.
|
||||||
if server.HasPermission(client, server.RootChannel(), RegisterPermission) {
|
rootChan := server.RootChannel()
|
||||||
|
if acl.HasPermission(&rootChan.ACL, client, acl.RegisterPermission) {
|
||||||
extended = true
|
extended = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the client wasn't granted extended permissions, only allow it to query
|
// If the client wasn't granted extended permissions, only allow it to query
|
||||||
// users in channels it can enter.
|
// users in channels it can enter.
|
||||||
if !extended && !server.HasPermission(client, target.Channel, EnterPermission) {
|
if !extended && !acl.HasPermission(&target.Channel.ACL, client, acl.EnterPermission) {
|
||||||
client.sendPermissionDenied(client, target.Channel, EnterPermission)
|
client.sendPermissionDenied(client, target.Channel, acl.EnterPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1318,7 +1325,7 @@ func (server *Server) handleUserStatsMessage(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
stats.Reset()
|
stats.Reset()
|
||||||
stats.Session = proto.Uint32(target.Session)
|
stats.Session = proto.Uint32(target.Session())
|
||||||
|
|
||||||
if details {
|
if details {
|
||||||
if tlsconn := target.conn.(*tls.Conn); tlsconn != nil {
|
if tlsconn := target.conn.(*tls.Conn); tlsconn != nil {
|
||||||
|
|
@ -1472,7 +1479,7 @@ func (server *Server) handleRequestBlob(client *Client, msg *Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userstate.Reset()
|
userstate.Reset()
|
||||||
userstate.Session = proto.Uint32(uint32(target.Session))
|
userstate.Session = proto.Uint32(uint32(target.Session()))
|
||||||
userstate.Texture = buf
|
userstate.Texture = buf
|
||||||
if err := client.sendMessage(userstate); err != nil {
|
if err := client.sendMessage(userstate); err != nil {
|
||||||
client.Panic(err)
|
client.Panic(err)
|
||||||
|
|
@ -1497,7 +1504,7 @@ func (server *Server) handleRequestBlob(client *Client, msg *Message) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
userstate.Reset()
|
userstate.Reset()
|
||||||
userstate.Session = proto.Uint32(uint32(target.Session))
|
userstate.Session = proto.Uint32(uint32(target.Session()))
|
||||||
userstate.Comment = proto.String(string(buf))
|
userstate.Comment = proto.String(string(buf))
|
||||||
if err := client.sendMessage(userstate); err != nil {
|
if err := client.sendMessage(userstate); err != nil {
|
||||||
client.Panic(err)
|
client.Panic(err)
|
||||||
|
|
@ -1543,8 +1550,9 @@ func (server *Server) handleUserList(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only users who are allowed to register other users can access the user list.
|
// Only users who are allowed to register other users can access the user list.
|
||||||
if !server.HasPermission(client, server.RootChannel(), RegisterPermission) {
|
rootChan := server.RootChannel()
|
||||||
client.sendPermissionDenied(client, server.RootChannel(), RegisterPermission)
|
if !acl.HasPermission(&rootChan.ACL, client, acl.RegisterPermission) {
|
||||||
|
client.sendPermissionDenied(client, rootChan, acl.RegisterPermission)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
25
murmurdb.go
25
murmurdb.go
|
|
@ -13,6 +13,7 @@ import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"errors"
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
"mumbleapp.com/grumble/pkg/ban"
|
"mumbleapp.com/grumble/pkg/ban"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -197,23 +198,23 @@ func populateChannelACLFromDatabase(server *Server, c *Channel, db *sql.DB) erro
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
acl := NewChannelACL(c)
|
aclEntry := acl.ACL{}
|
||||||
acl.ApplyHere = ApplyHere
|
aclEntry.ApplyHere = ApplyHere
|
||||||
acl.ApplySubs = ApplySub
|
aclEntry.ApplySubs = ApplySub
|
||||||
if len(UserId) > 0 {
|
if len(UserId) > 0 {
|
||||||
acl.UserId, err = strconv.Atoi(UserId)
|
aclEntry.UserId, err = strconv.Atoi(UserId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if len(Group) > 0 {
|
} else if len(Group) > 0 {
|
||||||
acl.Group = Group
|
aclEntry.Group = Group
|
||||||
} else {
|
} else {
|
||||||
return errors.New("Invalid ACL: Neither Group or UserId specified")
|
return errors.New("Invalid ACL: Neither Group or UserId specified")
|
||||||
}
|
}
|
||||||
|
|
||||||
acl.Deny = Permission(Deny)
|
aclEntry.Deny = acl.Permission(Deny)
|
||||||
acl.Allow = Permission(Allow)
|
aclEntry.Allow = acl.Permission(Allow)
|
||||||
c.ACL = append(c.ACL, acl)
|
c.ACL.ACLs = append(c.ACL.ACLs, aclEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -231,7 +232,7 @@ func populateChannelGroupsFromDatabase(server *Server, c *Channel, db *sql.DB) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
groups := make(map[int64]*Group)
|
groups := make(map[int64]acl.Group)
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var (
|
var (
|
||||||
|
|
@ -245,10 +246,10 @@ func populateChannelGroupsFromDatabase(server *Server, c *Channel, db *sql.DB) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
g := NewGroup(c, Name)
|
g := acl.EmptyGroupWithName(Name)
|
||||||
g.Inherit = Inherit
|
g.Inherit = Inherit
|
||||||
g.Inheritable = Inheritable
|
g.Inheritable = Inheritable
|
||||||
c.Groups[g.Name] = g
|
c.ACL.Groups[g.Name] = g
|
||||||
groups[GroupId] = g
|
groups[GroupId] = g
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,7 +315,7 @@ func populateChannelsFromDatabase(server *Server, db *sql.DB, parentId int) erro
|
||||||
|
|
||||||
c := NewChannel(chanid, name)
|
c := NewChannel(chanid, name)
|
||||||
server.Channels[c.Id] = c
|
server.Channels[c.Id] = c
|
||||||
c.InheritACL = inherit
|
c.ACL.InheritACL = inherit
|
||||||
parent.AddChild(c)
|
parent.AddChild(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
169
pkg/acl/acl.go
Normal file
169
pkg/acl/acl.go
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
// Copyright (c) 2010-2013 The Grumble Authors
|
||||||
|
// The use of this source code is goverened by a BSD-style
|
||||||
|
// license that can be found in the LICENSE-file.
|
||||||
|
|
||||||
|
package acl
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Per-channel permissions
|
||||||
|
NonePermission = 0x0
|
||||||
|
WritePermission = 0x1
|
||||||
|
TraversePermission = 0x2
|
||||||
|
EnterPermission = 0x4
|
||||||
|
SpeakPermission = 0x8
|
||||||
|
MuteDeafenPermission = 0x10
|
||||||
|
MovePermission = 0x20
|
||||||
|
MakeChannelPermission = 0x40
|
||||||
|
LinkChannelPermission = 0x80
|
||||||
|
WhisperPermission = 0x100
|
||||||
|
TextMessagePermission = 0x200
|
||||||
|
TempChannelPermission = 0x400
|
||||||
|
|
||||||
|
// Root channel only
|
||||||
|
KickPermission = 0x10000
|
||||||
|
BanPermission = 0x20000
|
||||||
|
RegisterPermission = 0x40000
|
||||||
|
SelfRegisterPermission = 0x80000
|
||||||
|
|
||||||
|
// Extra flags
|
||||||
|
CachedPermission = 0x8000000
|
||||||
|
AllPermissions = 0xf07ff
|
||||||
|
)
|
||||||
|
|
||||||
|
// Permission represents a permission in Mumble's ACL system.
|
||||||
|
type Permission uint32
|
||||||
|
|
||||||
|
// Check whether the given flags are set on perm
|
||||||
|
func (perm Permission) isSet(check Permission) bool {
|
||||||
|
return perm&check == check
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsCached checks whether the ACL has its cache bit set,
|
||||||
|
// signalling that it was returned from an ACLCache.
|
||||||
|
func (perm Permission) IsCached() bool {
|
||||||
|
return perm.isSet(CachedPermission)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean returns a Permission that has its cache bit cleared.
|
||||||
|
func (perm Permission) Clean() Permission {
|
||||||
|
return perm ^Permission(CachedPermission)
|
||||||
|
}
|
||||||
|
|
||||||
|
// An ACL as defined in an ACL context.
|
||||||
|
// An ACL can be defined for either a user or a group.
|
||||||
|
type ACL struct {
|
||||||
|
// The user id that this ACL applied to. If this
|
||||||
|
// field is -1, the ACL is a group ACL.
|
||||||
|
UserId int
|
||||||
|
// The group that this ACL applies to.
|
||||||
|
Group string
|
||||||
|
|
||||||
|
// The ApplyHere flag determines whether the ACL
|
||||||
|
// should apply to the current channel.
|
||||||
|
ApplyHere bool
|
||||||
|
// The ApplySubs flag determines whethr the ACL
|
||||||
|
// should apply to subchannels.
|
||||||
|
ApplySubs bool
|
||||||
|
|
||||||
|
// The allowed permission flags.
|
||||||
|
Allow Permission
|
||||||
|
// The allowed permission flags. The Deny flags override
|
||||||
|
// permissions set in Allow.
|
||||||
|
Deny Permission
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsUserACL returns true if the ACL is defined for a user,
|
||||||
|
// as opposed to a group.
|
||||||
|
func (acl *ACL) IsUserACL() bool {
|
||||||
|
return acl.UserId != -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsChannelACL returns true if the ACL is defined for a group,
|
||||||
|
// as opposed to a user.
|
||||||
|
func (acl *ACL) IsChannelACL() bool {
|
||||||
|
return !acl.IsUserACL()
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasPermission checks whether the given user has permission perm in the given context.
|
||||||
|
// The permission perm must be a single permission and not a combination of permissions.
|
||||||
|
func HasPermission(ctx *Context, user User, perm Permission) bool {
|
||||||
|
// We can't check permissions on a nil ctx.
|
||||||
|
if (ctx == nil) {
|
||||||
|
panic("acl: HasPermission got nil context")
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuperUser can't speak or whisper, but everything else is OK
|
||||||
|
if user.UserId() == 0 {
|
||||||
|
if perm == SpeakPermission || perm == WhisperPermission {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default permissions
|
||||||
|
defaults := Permission(TraversePermission | EnterPermission | SpeakPermission | WhisperPermission | TextMessagePermission)
|
||||||
|
granted := defaults
|
||||||
|
contexts := buildChain(ctx)
|
||||||
|
origCtx := ctx
|
||||||
|
|
||||||
|
traverse := true
|
||||||
|
write := false
|
||||||
|
|
||||||
|
for _, ctx := range contexts {
|
||||||
|
// If the context does not inherit any ACLs, use the default permissions.
|
||||||
|
if !ctx.InheritACL {
|
||||||
|
granted = defaults
|
||||||
|
}
|
||||||
|
// Iterate through ACLs that are defined on ctx. Note: this does not include
|
||||||
|
// ACLs that iter has inherited from a parent (unless there is also a group on
|
||||||
|
// iter with the same name, that changes the permissions a bit!)
|
||||||
|
for _, acl := range ctx.ACLs {
|
||||||
|
// Determine whether the ACL applies to user.
|
||||||
|
// If it is a user ACL and the user id of the ACL
|
||||||
|
// matches user's id, we're good to go.
|
||||||
|
//
|
||||||
|
// If it's a group ACL, we have to parse and interpret
|
||||||
|
// the group string in the current context to determine
|
||||||
|
// membership. For that we use GroupMemberCheck.
|
||||||
|
matchUser := acl.IsUserACL() && acl.UserId == user.UserId()
|
||||||
|
matchGroup := GroupMemberCheck(origCtx, ctx, acl.Group, user)
|
||||||
|
if matchUser || matchGroup {
|
||||||
|
if acl.Allow.isSet(TraversePermission) {
|
||||||
|
traverse = true
|
||||||
|
}
|
||||||
|
if acl.Deny.isSet(TraversePermission) {
|
||||||
|
traverse = false
|
||||||
|
}
|
||||||
|
if acl.Allow.isSet(WritePermission) {
|
||||||
|
write = true
|
||||||
|
}
|
||||||
|
if acl.Deny.isSet(WritePermission) {
|
||||||
|
write = false
|
||||||
|
}
|
||||||
|
if (origCtx == ctx && acl.ApplyHere) || (origCtx != ctx && acl.ApplySubs) {
|
||||||
|
granted |= acl.Allow
|
||||||
|
granted &= ^acl.Deny
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If traverse is not set and the user doesn't have write permissions
|
||||||
|
// on the channel, the user will not have any permissions.
|
||||||
|
// This is because -traverse removes all permissions, and +write grants
|
||||||
|
// all permissions.
|
||||||
|
if !traverse && !write {
|
||||||
|
granted = NonePermission
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The +write permission implies all permissions except for +speak and +whisper.
|
||||||
|
// This means that if the user has WritePermission, we should return true for all
|
||||||
|
// permissions exccept SpeakPermission and WhisperPermission.
|
||||||
|
if perm != SpeakPermission && perm != WhisperPermission {
|
||||||
|
return (granted & (perm | WritePermission)) != NonePermission
|
||||||
|
} else {
|
||||||
|
return (granted & perm) != NonePermission
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
48
pkg/acl/context.go
Normal file
48
pkg/acl/context.go
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (c) 2010-2013 The Grumble Authors
|
||||||
|
// The use of this source code is goverened by a BSD-style
|
||||||
|
// license that can be found in the LICENSE-file.
|
||||||
|
|
||||||
|
package acl
|
||||||
|
|
||||||
|
// Context represents a context in which ACLs can
|
||||||
|
// be understood. Typically embedded into a type
|
||||||
|
// that represents a Mumble channel.
|
||||||
|
type Context struct {
|
||||||
|
// Parent points to the context's parent.
|
||||||
|
// May be nil if the Context does not have a parent.
|
||||||
|
Parent *Context
|
||||||
|
|
||||||
|
// ACLs is the Context's list of ACL entries.
|
||||||
|
ACLs []ACL
|
||||||
|
|
||||||
|
// Groups is the Context's representation of groups.
|
||||||
|
// It is indexed by the Group's name.
|
||||||
|
Groups map[string]Group
|
||||||
|
|
||||||
|
// InheritACL determines whether this context should
|
||||||
|
// inherit ACLs from its parent.
|
||||||
|
InheritACL bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// indexOf finds the index of the context ctx in the context chain contexts.
|
||||||
|
// Returns -1 if the given context was not found in the context chain.
|
||||||
|
func indexOf(contexts []*Context, ctx *Context) int {
|
||||||
|
for i, iter := range contexts {
|
||||||
|
if iter == ctx {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// buildChain walks from the context ctx back through all of its parents,
|
||||||
|
// collecting them all in a slice. The first element of the returned
|
||||||
|
// slice is the final ancestor (it has a nil Parent).
|
||||||
|
func buildChain(ctx *Context) []*Context {
|
||||||
|
chain := []*Context{}
|
||||||
|
for ctx != nil {
|
||||||
|
chain = append([]*Context{ctx}, chain...)
|
||||||
|
ctx = ctx.Parent
|
||||||
|
}
|
||||||
|
return chain
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
// Copyright (c) 2010 The Grumble Authors
|
// Copyright (c) 2010-2013 The Grumble Authors
|
||||||
// The use of this source code is goverened by a BSD-style
|
// The use of this source code is goverened by a BSD-style
|
||||||
// license that can be found in the LICENSE-file.
|
// license that can be found in the LICENSE-file.
|
||||||
|
package acl
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -10,10 +9,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Group represents a Group in an Context.
|
||||||
type Group struct {
|
type Group struct {
|
||||||
// The channel that this group resides in
|
|
||||||
Channel *Channel
|
|
||||||
|
|
||||||
// The name of this group
|
// The name of this group
|
||||||
Name string
|
Name string
|
||||||
|
|
||||||
|
|
@ -33,11 +30,9 @@ type Group struct {
|
||||||
Temporary map[int]bool
|
Temporary map[int]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new group for channel with name. Does not add it to the channels
|
// EmptyGroupWithName creates a new Group with the given name.
|
||||||
// group list.
|
func EmptyGroupWithName(name string) Group {
|
||||||
func NewGroup(channel *Channel, name string) *Group {
|
grp := Group{}
|
||||||
grp := &Group{}
|
|
||||||
grp.Channel = channel
|
|
||||||
grp.Name = name
|
grp.Name = name
|
||||||
grp.Add = make(map[int]bool)
|
grp.Add = make(map[int]bool)
|
||||||
grp.Remove = make(map[int]bool)
|
grp.Remove = make(map[int]bool)
|
||||||
|
|
@ -45,13 +40,13 @@ func NewGroup(channel *Channel, name string) *Group {
|
||||||
return grp
|
return grp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the Add set contains id.
|
// AddContains checks whether the Add set contains id.
|
||||||
func (group *Group) AddContains(id int) (ok bool) {
|
func (group *Group) AddContains(id int) (ok bool) {
|
||||||
_, ok = group.Add[id]
|
_, ok = group.Add[id]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of user ids in the Add set.
|
// AddUsers gets the list of user ids in the Add set.
|
||||||
func (group *Group) AddUsers() []int {
|
func (group *Group) AddUsers() []int {
|
||||||
users := []int{}
|
users := []int{}
|
||||||
for uid, _ := range group.Add {
|
for uid, _ := range group.Add {
|
||||||
|
|
@ -60,13 +55,13 @@ func (group *Group) AddUsers() []int {
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the Remove set contains id.
|
// RemoveContains checks whether the Remove set contains id.
|
||||||
func (group *Group) RemoveContains(id int) (ok bool) {
|
func (group *Group) RemoveContains(id int) (ok bool) {
|
||||||
_, ok = group.Remove[id]
|
_, ok = group.Remove[id]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of user ids in the Remove set.
|
// RemoveUsers gets the list of user ids in the Remove set.
|
||||||
func (group *Group) RemoveUsers() []int {
|
func (group *Group) RemoveUsers() []int {
|
||||||
users := []int{}
|
users := []int{}
|
||||||
for uid, _ := range group.Remove {
|
for uid, _ := range group.Remove {
|
||||||
|
|
@ -75,41 +70,38 @@ func (group *Group) RemoveUsers() []int {
|
||||||
return users
|
return users
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the Temporary set contains id.
|
// TemporaryContains checks whether the Temporary set contains id.
|
||||||
func (group *Group) TemporaryContains(id int) (ok bool) {
|
func (group *Group) TemporaryContains(id int) (ok bool) {
|
||||||
_, ok = group.Temporary[id]
|
_, ok = group.Temporary[id]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the set of user id's from the group. This includes group
|
// MembersInContext gets the set of user id's from the group in the given context.
|
||||||
// members that have been inherited from an ancestor.
|
// This includes group members that have been inherited from an ancestor context.
|
||||||
func (group *Group) Members() map[int]bool {
|
func (group *Group) MembersInContext(ctx *Context) map[int]bool {
|
||||||
groups := []*Group{}
|
groups := []Group{}
|
||||||
members := map[int]bool{}
|
members := map[int]bool{}
|
||||||
|
|
||||||
// The channel that the group is defined on.
|
// Walk a group's context chain, starting with the context the group
|
||||||
channel := group.Channel
|
// is defined on, followed by its parent contexts.
|
||||||
|
origCtx := ctx
|
||||||
// Walk a group's channel tree, starting with the channel the group
|
for ctx != nil {
|
||||||
// is defined on, followed by its parent channels.
|
curgroup, ok := ctx.Groups[group.Name]
|
||||||
iter := group.Channel
|
if ok {
|
||||||
for iter != nil {
|
|
||||||
curgroup := iter.Groups[group.Name]
|
|
||||||
if curgroup != nil {
|
|
||||||
// If the group is not inheritable, and we're looking at an
|
// If the group is not inheritable, and we're looking at an
|
||||||
// ancestor group, we've looked in all the groups we should.
|
// ancestor group, we've looked in all the groups we should.
|
||||||
if iter != channel && !curgroup.Inheritable {
|
if ctx != origCtx && !curgroup.Inheritable {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Add the group to the list of groups to be considered
|
// Add the group to the list of groups to be considered
|
||||||
groups = append([]*Group{curgroup}, groups...)
|
groups = append([]Group{curgroup}, groups...)
|
||||||
// If this group does not inherit from groups in its ancestors, stop looking
|
// If this group does not inherit from groups in its ancestors, stop looking
|
||||||
// for more ancestor groups.
|
// for more ancestor groups.
|
||||||
if !curgroup.Inherit {
|
if !curgroup.Inherit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter = iter.parent
|
ctx = ctx.Parent
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, curgroup := range groups {
|
for _, curgroup := range groups {
|
||||||
|
|
@ -124,13 +116,18 @@ func (group *Group) Members() map[int]bool {
|
||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks whether a user is a member of the group as defined on channel.
|
// GroupMemberCheck checks whether a user is a member
|
||||||
// The channel current is the channel that group membership is currently being evaluated for.
|
// of the group as defined in the given context.
|
||||||
// The channel aclchan is the channel that the group is defined on. This means that current inherits
|
|
||||||
// the group from an acl in aclchan.
|
|
||||||
//
|
//
|
||||||
// The channel aclchan will always be either equal to current, or be an ancestor.
|
// The 'current' context is the context that group
|
||||||
func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *Client) (ok bool) {
|
// membership is currently being evaluated for.
|
||||||
|
//
|
||||||
|
// The 'acl' context is the context of the ACL that
|
||||||
|
// that group membership is being evaluated for.
|
||||||
|
//
|
||||||
|
// The acl context will always be either equal to
|
||||||
|
// current, or be an ancestor.
|
||||||
|
func GroupMemberCheck(current *Context, acl *Context, name string, user User) (ok bool) {
|
||||||
valid := true
|
valid := true
|
||||||
invert := false
|
invert := false
|
||||||
token := false
|
token := false
|
||||||
|
|
@ -160,7 +157,7 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
}
|
}
|
||||||
// Evaluate in ACL context (not current channel)
|
// Evaluate in ACL context (not current channel)
|
||||||
if name[0] == '~' {
|
if name[0] == '~' {
|
||||||
channel = aclchan
|
channel = acl
|
||||||
name = name[1:]
|
name = name[1:]
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -182,8 +179,8 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
if token {
|
if token {
|
||||||
// The user is part of this group if the remaining name is part of
|
// The user is part of this group if the remaining name is part of
|
||||||
// his access token list. The name check is case-insensitive.
|
// his access token list. The name check is case-insensitive.
|
||||||
for _, clientToken := range client.Tokens {
|
for _, token := range user.Tokens() {
|
||||||
if strings.ToLower(name) == strings.ToLower(clientToken) {
|
if strings.ToLower(name) == strings.ToLower(token) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -191,7 +188,7 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
} else if hash {
|
} else if hash {
|
||||||
// The client is part of this group if the remaining name matches the
|
// The client is part of this group if the remaining name matches the
|
||||||
// client's cert hash.
|
// client's cert hash.
|
||||||
if strings.ToLower(name) == strings.ToLower(client.CertHash) {
|
if strings.ToLower(name) == strings.ToLower(user.CertHash()) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|
@ -204,7 +201,7 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
} else if name == "auth" {
|
} else if name == "auth" {
|
||||||
// The user is part of the auth group is he is authenticated. That is,
|
// The user is part of the auth group is he is authenticated. That is,
|
||||||
// his UserId is >= 0.
|
// his UserId is >= 0.
|
||||||
return client.IsRegistered()
|
return user.UserId() >= 0
|
||||||
} else if name == "strong" {
|
} else if name == "strong" {
|
||||||
// The user is part of the strong group if he is authenticated to the server
|
// The user is part of the strong group if he is authenticated to the server
|
||||||
// via a strong certificate (i.e. non-self-signed, trusted by the server's
|
// via a strong certificate (i.e. non-self-signed, trusted by the server's
|
||||||
|
|
@ -213,10 +210,10 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
return false
|
return false
|
||||||
} else if name == "in" {
|
} else if name == "in" {
|
||||||
// Is the user in the currently evaluated channel?
|
// Is the user in the currently evaluated channel?
|
||||||
return client.Channel == channel
|
return user.ACLContext() == channel
|
||||||
} else if name == "out" {
|
} else if name == "out" {
|
||||||
// Is the user not in the currently evaluated channel?
|
// Is the user not in the currently evaluated channel?
|
||||||
return client.Channel != channel
|
return user.ACLContext() != channel
|
||||||
} else if name == "sub" {
|
} else if name == "sub" {
|
||||||
// fixme(mkrautz): The sub group implementation below hasn't been thoroughly
|
// fixme(mkrautz): The sub group implementation below hasn't been thoroughly
|
||||||
// tested yet. It might be a bit buggy!
|
// tested yet. It might be a bit buggy!
|
||||||
|
|
@ -255,45 +252,30 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a chain of channels, starting from the client's current channel.
|
// Build a context chain starting from the
|
||||||
playerChain := []*Channel{}
|
// user's current context.
|
||||||
iter := client.Channel
|
userChain := buildChain(user.ACLContext())
|
||||||
for iter != nil {
|
// Build a chain of contexts, starting from
|
||||||
playerChain = append([]*Channel{iter}, playerChain...)
|
// the 'current' context. This is the context
|
||||||
iter = iter.parent
|
// that group membership is checked against,
|
||||||
}
|
// notwithstanding the ~ group operator.
|
||||||
// Build a chain of channels, starting from the channel current. This is
|
groupChain := buildChain(current)
|
||||||
// the channel that group membership is checked against, notwithstanding
|
|
||||||
// the ~ group operator.
|
|
||||||
groupChain := []*Channel{}
|
|
||||||
iter = current
|
|
||||||
for iter != nil {
|
|
||||||
groupChain = append([]*Channel{iter}, groupChain...)
|
|
||||||
iter = iter.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function that finds the given channel in the channels slice.
|
// Find the index of the context that the group
|
||||||
// Returns -1 if the given channel was not found in the slice.
|
// is currently being evaluated on. This can be
|
||||||
indexOf := func(channels []*Channel, channel *Channel) int {
|
// either the 'acl' context or 'current' context
|
||||||
for i, iter := range channels {
|
// depending on the ~ group operator.
|
||||||
if iter == channel {
|
cofs := indexOf(groupChain, current)
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the index of channel that the group is currently being evaluated on.
|
|
||||||
// This can be either aclchan or current depending on the ~ group operator.
|
|
||||||
cofs := indexOf(groupChain, channel)
|
|
||||||
if cofs == -1 {
|
if cofs == -1 {
|
||||||
valid = false
|
valid = false
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the first parameter of our sub group to cofs to get our 'base' channel.
|
// Add the first parameter of our sub group to cofs
|
||||||
|
// to get our base context.
|
||||||
cofs += minpath
|
cofs += minpath
|
||||||
// Check that the minpath parameter that was given is a valid index for groupChain.
|
// Check that the minpath parameter that was given
|
||||||
|
// is a valid index for groupChain.
|
||||||
if cofs >= len(groupChain) {
|
if cofs >= len(groupChain) {
|
||||||
valid = false
|
valid = false
|
||||||
return false
|
return false
|
||||||
|
|
@ -301,48 +283,50 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
cofs = 0
|
cofs = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// If our 'base' channel is not in the playerChain, the group does not apply to the client.
|
// If our base context is not in the userChain, the
|
||||||
if indexOf(playerChain, groupChain[cofs]) == -1 {
|
// group does not apply to the user.
|
||||||
|
if indexOf(userChain, groupChain[cofs]) == -1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Down here, we're certain that the playerChain includes the base channel
|
// Down here, we're certain that the userChain
|
||||||
// *somewhere*. We must now determine if the path depth makes the user a
|
// includes the base context somewhere in its
|
||||||
// member of the group.
|
// chain. We must now determine if the path depth
|
||||||
|
// makes the user a member of the group.
|
||||||
mindepth := cofs + mindesc
|
mindepth := cofs + mindesc
|
||||||
maxdepth := cofs + maxdesc
|
maxdepth := cofs + maxdesc
|
||||||
pdepth := len(playerChain) - 1
|
pdepth := len(userChain) - 1
|
||||||
return pdepth >= mindepth && pdepth <= maxdepth
|
return pdepth >= mindepth && pdepth <= maxdepth
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Non-magic groups
|
// Non-magic groups
|
||||||
groups := []*Group{}
|
groups := []Group{}
|
||||||
|
|
||||||
iter := channel
|
iter := channel
|
||||||
for iter != nil {
|
for iter != nil {
|
||||||
if group, ok := iter.Groups[name]; ok {
|
if group, ok := iter.Groups[name]; ok {
|
||||||
// Skip non-inheritable groups if we're in parents
|
// Skip non-inheritable groups if we're in parents
|
||||||
// of our evaluated channel.
|
// of our evaluated context.
|
||||||
if iter != channel && !group.Inheritable {
|
if iter != channel && !group.Inheritable {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Prepend group
|
// Prepend group
|
||||||
groups = append([]*Group{group}, groups...)
|
groups = append([]Group{group}, groups...)
|
||||||
// If this group does not inherit from groups in its ancestors, stop looking
|
// If this group does not inherit from groups in its ancestors, stop looking
|
||||||
// for more ancestor groups.
|
// for more ancestor groups.
|
||||||
if !group.Inherit {
|
if !group.Inherit {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iter = iter.parent
|
iter = iter.Parent
|
||||||
}
|
}
|
||||||
|
|
||||||
isMember := false
|
isMember := false
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
if group.AddContains(client.UserId()) || group.TemporaryContains(client.UserId()) || group.TemporaryContains(-int(client.Session)) {
|
if group.AddContains(user.UserId()) || group.TemporaryContains(user.UserId()) || group.TemporaryContains(-int(user.Session())) {
|
||||||
isMember = true
|
isMember = true
|
||||||
}
|
}
|
||||||
if group.RemoveContains(client.UserId()) {
|
if group.RemoveContains(user.UserId()) {
|
||||||
isMember = false
|
isMember = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -352,28 +336,21 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the list of group names in a particular channel.
|
// Get the list of group names for the given ACL context.
|
||||||
// This function walks the through the channel and all its
|
//
|
||||||
// parent channels to figure out all groups that affect
|
// This function walks the through the context chain to figure
|
||||||
// the channel while considering group inheritance.
|
// out all groups that affect the given context whilst considering
|
||||||
func (channel *Channel) GroupNames() map[string]bool {
|
// group inheritance.
|
||||||
|
func (ctx *Context) GroupNames() []string {
|
||||||
names := map[string]bool{}
|
names := map[string]bool{}
|
||||||
|
origCtx := ctx
|
||||||
|
contexts := []*Context{}
|
||||||
|
|
||||||
// Construct a list of channels. Fartherst away ancestors
|
// Walk through the whole context chain and all groups in it.
|
||||||
// are put in front of the list, allowing us to linearly
|
for _, ctx := range contexts {
|
||||||
// iterate the list to determine inheritance.
|
for _, group := range ctx.Groups {
|
||||||
channels := []*Channel{}
|
|
||||||
iter := channel
|
|
||||||
for iter != nil {
|
|
||||||
channels = append([]*Channel{iter}, channels...)
|
|
||||||
iter = iter.parent
|
|
||||||
}
|
|
||||||
|
|
||||||
// Walk through all channels and groups in them.
|
|
||||||
for _, iter := range channels {
|
|
||||||
for _, group := range iter.Groups {
|
|
||||||
// A non-inheritable group in parent. Discard it.
|
// A non-inheritable group in parent. Discard it.
|
||||||
if channel != iter && !group.Inheritable {
|
if ctx != origCtx && !group.Inheritable {
|
||||||
delete(names, group.Name)
|
delete(names, group.Name)
|
||||||
// An inheritable group. Add it to the list.
|
// An inheritable group. Add it to the list.
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -381,5 +358,13 @@ func (channel *Channel) GroupNames() map[string]bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return names
|
|
||||||
|
// Convert to slice
|
||||||
|
stringNames := make([]string, 0, len(names))
|
||||||
|
for name, ok := range names {
|
||||||
|
if ok {
|
||||||
|
stringNames = append(stringNames, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stringNames
|
||||||
}
|
}
|
||||||
23
pkg/acl/interfaces.go
Normal file
23
pkg/acl/interfaces.go
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) 2013 The Grumble Authors
|
||||||
|
// The use of this source code is goverened by a BSD-style
|
||||||
|
// license that can be found in the LICENSE-file.
|
||||||
|
|
||||||
|
package acl
|
||||||
|
|
||||||
|
// User represents a user on a Mumble server.
|
||||||
|
// The User interface represents the method set that
|
||||||
|
// must be implemented in order to check a user's
|
||||||
|
// permissions in an ACL context.
|
||||||
|
type User interface {
|
||||||
|
Session() uint32
|
||||||
|
UserId() int
|
||||||
|
|
||||||
|
CertHash() string
|
||||||
|
Tokens() []string
|
||||||
|
ACLContext() *Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// Channel represents a Channel on a Mumble server.
|
||||||
|
type Channel interface {
|
||||||
|
ChannelId() int
|
||||||
|
}
|
||||||
103
server.go
103
server.go
|
|
@ -17,6 +17,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"log"
|
"log"
|
||||||
|
"mumbleapp.com/grumble/pkg/acl"
|
||||||
"mumbleapp.com/grumble/pkg/ban"
|
"mumbleapp.com/grumble/pkg/ban"
|
||||||
"mumbleapp.com/grumble/pkg/freezer"
|
"mumbleapp.com/grumble/pkg/freezer"
|
||||||
"mumbleapp.com/grumble/pkg/htmlfilter"
|
"mumbleapp.com/grumble/pkg/htmlfilter"
|
||||||
|
|
@ -107,9 +108,6 @@ type Server struct {
|
||||||
numLogOps int
|
numLogOps int
|
||||||
freezelog *freezer.Log
|
freezelog *freezer.Log
|
||||||
|
|
||||||
// ACL cache
|
|
||||||
aclcache ACLCache
|
|
||||||
|
|
||||||
// Bans
|
// Bans
|
||||||
banlock sync.RWMutex
|
banlock sync.RWMutex
|
||||||
Bans []ban.Ban
|
Bans []ban.Ban
|
||||||
|
|
@ -125,7 +123,7 @@ type clientLogForwarder struct {
|
||||||
|
|
||||||
func (lf clientLogForwarder) Write(incoming []byte) (int, error) {
|
func (lf clientLogForwarder) Write(incoming []byte) (int, error) {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
buf.WriteString(fmt.Sprintf("<%v:%v(%v)> ", lf.client.Session, lf.client.ShownName(), lf.client.UserId()))
|
buf.WriteString(fmt.Sprintf("<%v:%v(%v)> ", lf.client.Session(), lf.client.ShownName(), lf.client.UserId()))
|
||||||
buf.Write(incoming)
|
buf.Write(incoming)
|
||||||
lf.logger.Output(3, buf.String())
|
lf.logger.Output(3, buf.String())
|
||||||
return len(incoming), nil
|
return len(incoming), nil
|
||||||
|
|
@ -147,7 +145,6 @@ func NewServer(id int64) (s *Server, err error) {
|
||||||
s.nextUserId = 1
|
s.nextUserId = 1
|
||||||
|
|
||||||
s.Channels = make(map[int]*Channel)
|
s.Channels = make(map[int]*Channel)
|
||||||
s.aclcache = NewACLCache()
|
|
||||||
s.Channels[0] = NewChannel(0, "Root")
|
s.Channels[0] = NewChannel(0, "Root")
|
||||||
s.nextChanId = 1
|
s.nextChanId = 1
|
||||||
|
|
||||||
|
|
@ -238,8 +235,8 @@ func (server *Server) handleIncomingClient(conn net.Conn) (err error) {
|
||||||
client.lf = &clientLogForwarder{client, server.Logger}
|
client.lf = &clientLogForwarder{client, server.Logger}
|
||||||
client.Logger = log.New(client.lf, "", 0)
|
client.Logger = log.New(client.lf, "", 0)
|
||||||
|
|
||||||
client.Session = server.pool.Get()
|
client.session = server.pool.Get()
|
||||||
client.Printf("New connection: %v (%v)", conn.RemoteAddr(), client.Session)
|
client.Printf("New connection: %v (%v)", conn.RemoteAddr(), client.Session())
|
||||||
|
|
||||||
client.tcpaddr = addr.(*net.TCPAddr)
|
client.tcpaddr = addr.(*net.TCPAddr)
|
||||||
client.server = server
|
client.server = server
|
||||||
|
|
@ -263,15 +260,17 @@ func (server *Server) handleIncomingClient(conn net.Conn) (err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
state := tlsconn.ConnectionState()
|
state := tlsconn.ConnectionState()
|
||||||
|
log.Printf("peerCerts = %#v", state.PeerCertificates)
|
||||||
if len(state.PeerCertificates) > 0 {
|
if len(state.PeerCertificates) > 0 {
|
||||||
hash := sha1.New()
|
hash := sha1.New()
|
||||||
hash.Write(state.PeerCertificates[0].Raw)
|
hash.Write(state.PeerCertificates[0].Raw)
|
||||||
sum := hash.Sum(nil)
|
sum := hash.Sum(nil)
|
||||||
client.CertHash = hex.EncodeToString(sum)
|
client.certHash = hex.EncodeToString(sum)
|
||||||
|
log.Printf("%v", client.CertHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the client's cert hash is banned
|
// Check whether the client's cert hash is banned
|
||||||
if server.IsCertHashBanned(client.CertHash) {
|
if server.IsCertHashBanned(client.CertHash()) {
|
||||||
client.Printf("Certificate hash is banned")
|
client.Printf("Certificate hash is banned")
|
||||||
client.Disconnect()
|
client.Disconnect()
|
||||||
return
|
return
|
||||||
|
|
@ -302,8 +301,8 @@ func (server *Server) RemoveClient(client *Client, kicked bool) {
|
||||||
}
|
}
|
||||||
server.hmutex.Unlock()
|
server.hmutex.Unlock()
|
||||||
|
|
||||||
delete(server.clients, client.Session)
|
delete(server.clients, client.Session())
|
||||||
server.pool.Reclaim(client.Session)
|
server.pool.Reclaim(client.Session())
|
||||||
|
|
||||||
// Remove client from channel
|
// Remove client from channel
|
||||||
channel := client.Channel
|
channel := client.Channel
|
||||||
|
|
@ -316,7 +315,7 @@ func (server *Server) RemoveClient(client *Client, kicked bool) {
|
||||||
// at this point.
|
// at this point.
|
||||||
if !kicked && client.state > StateClientAuthenticated {
|
if !kicked && client.state > StateClientAuthenticated {
|
||||||
err := server.broadcastProtoMessage(&mumbleproto.UserRemove{
|
err := server.broadcastProtoMessage(&mumbleproto.UserRemove{
|
||||||
Session: proto.Uint32(client.Session),
|
Session: proto.Uint32(client.Session()),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
server.Panic("Unable to broadcast UserRemove message for disconnected client.")
|
server.Panic("Unable to broadcast UserRemove message for disconnected client.")
|
||||||
|
|
@ -449,7 +448,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
// Set access tokens. Clients can set their access tokens any time
|
// Set access tokens. Clients can set their access tokens any time
|
||||||
// by sending an Authenticate message with he contents of their new
|
// by sending an Authenticate message with he contents of their new
|
||||||
// access token list.
|
// access token list.
|
||||||
client.Tokens = auth.Tokens
|
client.tokens = auth.Tokens
|
||||||
server.ClearCaches()
|
server.ClearCaches()
|
||||||
|
|
||||||
if client.state >= StateClientAuthenticated {
|
if client.state >= StateClientAuthenticated {
|
||||||
|
|
@ -485,7 +484,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
// First look up registration by name.
|
// First look up registration by name.
|
||||||
user, exists := server.UserNameMap[client.Username]
|
user, exists := server.UserNameMap[client.Username]
|
||||||
if exists {
|
if exists {
|
||||||
if len(client.CertHash) > 0 && user.CertHash == client.CertHash {
|
if client.HasCertificate() && user.CertHash == client.CertHash() {
|
||||||
client.user = user
|
client.user = user
|
||||||
} else {
|
} else {
|
||||||
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "Wrong certificate hash")
|
client.RejectAuth(mumbleproto.Reject_WrongUserPW, "Wrong certificate hash")
|
||||||
|
|
@ -494,8 +493,8 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name matching didn't do. Try matching by certificate.
|
// Name matching didn't do. Try matching by certificate.
|
||||||
if client.user == nil && len(client.CertHash) > 0 {
|
if client.user == nil && client.HasCertificate() {
|
||||||
user, exists := server.UserCertMap[client.CertHash]
|
user, exists := server.UserCertMap[client.CertHash()]
|
||||||
if exists {
|
if exists {
|
||||||
client.user = user
|
client.user = user
|
||||||
}
|
}
|
||||||
|
|
@ -557,15 +556,15 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the client to the connected list
|
// Add the client to the connected list
|
||||||
server.clients[client.Session] = client
|
server.clients[client.Session()] = client
|
||||||
|
|
||||||
// Warn clients without CELT support that they might not be able to talk to everyone else.
|
// Warn clients without CELT support that they might not be able to talk to everyone else.
|
||||||
if len(client.codecs) == 0 {
|
if len(client.codecs) == 0 {
|
||||||
client.codecs = []int32{CeltCompatBitstream}
|
client.codecs = []int32{CeltCompatBitstream}
|
||||||
server.Printf("Client %v connected without CELT codecs. Faking compat bitstream.", client.Session)
|
server.Printf("Client %v connected without CELT codecs. Faking compat bitstream.", client.Session())
|
||||||
if server.Opus && !client.opus {
|
if server.Opus && !client.opus {
|
||||||
client.sendMessage(&mumbleproto.TextMessage{
|
client.sendMessage(&mumbleproto.TextMessage{
|
||||||
Session: []uint32{client.Session},
|
Session: []uint32{client.Session()},
|
||||||
Message: proto.String("<strong>WARNING:</strong> Your client doesn't support the CELT codec, you won't be able to talk to or hear most clients. Please make sure your client was built with CELT support."),
|
Message: proto.String("<strong>WARNING:</strong> Your client doesn't support the CELT codec, you won't be able to talk to or hear most clients. Please make sure your client was built with CELT support."),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -592,13 +591,13 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
userstate := &mumbleproto.UserState{
|
userstate := &mumbleproto.UserState{
|
||||||
Session: proto.Uint32(client.Session),
|
Session: proto.Uint32(client.Session()),
|
||||||
Name: proto.String(client.ShownName()),
|
Name: proto.String(client.ShownName()),
|
||||||
ChannelId: proto.Uint32(uint32(channel.Id)),
|
ChannelId: proto.Uint32(uint32(channel.Id)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(client.CertHash) > 0 {
|
if client.HasCertificate() {
|
||||||
userstate.Hash = proto.String(client.CertHash)
|
userstate.Hash = proto.String(client.CertHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if client.IsRegistered() {
|
if client.IsRegistered() {
|
||||||
|
|
@ -639,20 +638,18 @@ func (server *Server) finishAuthenticate(client *Client) {
|
||||||
server.sendUserList(client)
|
server.sendUserList(client)
|
||||||
|
|
||||||
sync := &mumbleproto.ServerSync{}
|
sync := &mumbleproto.ServerSync{}
|
||||||
sync.Session = proto.Uint32(client.Session)
|
sync.Session = proto.Uint32(client.Session())
|
||||||
sync.MaxBandwidth = proto.Uint32(server.cfg.Uint32Value("MaxBandwidth"))
|
sync.MaxBandwidth = proto.Uint32(server.cfg.Uint32Value("MaxBandwidth"))
|
||||||
sync.WelcomeText = proto.String(server.cfg.StringValue("WelcomeText"))
|
sync.WelcomeText = proto.String(server.cfg.StringValue("WelcomeText"))
|
||||||
if client.IsSuperUser() {
|
if client.IsSuperUser() {
|
||||||
sync.Permissions = proto.Uint64(uint64(AllPermissions))
|
sync.Permissions = proto.Uint64(uint64(acl.AllPermissions))
|
||||||
} else {
|
} else {
|
||||||
server.HasPermission(client, server.RootChannel(), EnterPermission)
|
// fixme(mkrautz): previously we calculated the user's
|
||||||
perm := server.aclcache.GetPermission(client, server.RootChannel())
|
// permissions and sent them to the client in here. This
|
||||||
if !perm.IsCached() {
|
// code relied on our ACL cache, but that has been temporarily
|
||||||
client.Panic("Corrupt ACL cache")
|
// thrown out because of our ACL handling code moving to its
|
||||||
return
|
// own package.
|
||||||
}
|
sync.Permissions = nil
|
||||||
perm.ClearCacheBit()
|
|
||||||
sync.Permissions = proto.Uint64(uint64(perm))
|
|
||||||
}
|
}
|
||||||
if err := client.sendMessage(sync); err != nil {
|
if err := client.sendMessage(sync); err != nil {
|
||||||
client.Panicf("%v", err)
|
client.Panicf("%v", err)
|
||||||
|
|
@ -729,7 +726,7 @@ func (server *Server) updateCodecVersions(connecting *Client) {
|
||||||
}
|
}
|
||||||
} else if server.Opus == enableOpus {
|
} else if server.Opus == enableOpus {
|
||||||
if server.Opus && connecting != nil && !connecting.opus {
|
if server.Opus && connecting != nil && !connecting.opus {
|
||||||
txtMsg.Session = []uint32{connecting.Session}
|
txtMsg.Session = []uint32{connecting.Session()}
|
||||||
connecting.sendMessage(txtMsg)
|
connecting.sendMessage(txtMsg)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|
@ -751,7 +748,7 @@ func (server *Server) updateCodecVersions(connecting *Client) {
|
||||||
if server.Opus {
|
if server.Opus {
|
||||||
for _, client := range server.clients {
|
for _, client := range server.clients {
|
||||||
if !client.opus && client.state == StateClientReady {
|
if !client.opus && client.state == StateClientReady {
|
||||||
txtMsg.Session = []uint32{connecting.Session}
|
txtMsg.Session = []uint32{connecting.Session()}
|
||||||
err := client.sendMessage(txtMsg)
|
err := client.sendMessage(txtMsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
client.Panicf("%v", err)
|
client.Panicf("%v", err)
|
||||||
|
|
@ -759,7 +756,7 @@ func (server *Server) updateCodecVersions(connecting *Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if connecting != nil && !connecting.opus {
|
if connecting != nil && !connecting.opus {
|
||||||
txtMsg.Session = []uint32{connecting.Session}
|
txtMsg.Session = []uint32{connecting.Session()}
|
||||||
connecting.sendMessage(txtMsg)
|
connecting.sendMessage(txtMsg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -778,13 +775,13 @@ func (server *Server) sendUserList(client *Client) {
|
||||||
}
|
}
|
||||||
|
|
||||||
userstate := &mumbleproto.UserState{
|
userstate := &mumbleproto.UserState{
|
||||||
Session: proto.Uint32(connectedClient.Session),
|
Session: proto.Uint32(connectedClient.Session()),
|
||||||
Name: proto.String(connectedClient.ShownName()),
|
Name: proto.String(connectedClient.ShownName()),
|
||||||
ChannelId: proto.Uint32(uint32(connectedClient.Channel.Id)),
|
ChannelId: proto.Uint32(uint32(connectedClient.Channel.Id)),
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(connectedClient.CertHash) > 0 {
|
if connectedClient.HasCertificate() {
|
||||||
userstate.Hash = proto.String(connectedClient.CertHash)
|
userstate.Hash = proto.String(connectedClient.CertHash())
|
||||||
}
|
}
|
||||||
|
|
||||||
if connectedClient.IsRegistered() {
|
if connectedClient.IsRegistered() {
|
||||||
|
|
@ -857,11 +854,10 @@ func (server *Server) sendClientPermissions(client *Client, channel *Channel) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update cache
|
// fixme(mkrautz): re-add when we have ACL caching
|
||||||
server.HasPermission(client, channel, EnterPermission)
|
return
|
||||||
perm := server.aclcache.GetPermission(client, channel)
|
|
||||||
|
|
||||||
// fixme(mkrautz): Cache which permissions we've already sent.
|
perm := acl.Permission(acl.NonePermission)
|
||||||
client.sendMessage(&mumbleproto.PermissionQuery{
|
client.sendMessage(&mumbleproto.PermissionQuery{
|
||||||
ChannelId: proto.Uint32(uint32(channel.Id)),
|
ChannelId: proto.Uint32(uint32(channel.Id)),
|
||||||
Permissions: proto.Uint32(uint32(perm)),
|
Permissions: proto.Uint32(uint32(perm)),
|
||||||
|
|
@ -1038,7 +1034,6 @@ func (server *Server) handleUdpPacket(udpaddr *net.UDPAddr, buf []byte, nread in
|
||||||
|
|
||||||
// Clear the Server's caches
|
// Clear the Server's caches
|
||||||
func (server *Server) ClearCaches() {
|
func (server *Server) ClearCaches() {
|
||||||
server.aclcache = NewACLCache()
|
|
||||||
for _, client := range server.clients {
|
for _, client := range server.clients {
|
||||||
client.ClearCaches()
|
client.ClearCaches()
|
||||||
}
|
}
|
||||||
|
|
@ -1063,7 +1058,7 @@ func (server *Server) userEnterChannel(client *Client, channel *Channel, usersta
|
||||||
|
|
||||||
server.UpdateFrozenUserLastChannel(client)
|
server.UpdateFrozenUserLastChannel(client)
|
||||||
|
|
||||||
canspeak := server.HasPermission(client, channel, SpeakPermission)
|
canspeak := acl.HasPermission(&channel.ACL, client, acl.SpeakPermission)
|
||||||
if canspeak == client.Suppress {
|
if canspeak == client.Suppress {
|
||||||
client.Suppress = !canspeak
|
client.Suppress = !canspeak
|
||||||
userstate.Suppress = proto.Bool(client.Suppress)
|
userstate.Suppress = proto.Bool(client.Suppress)
|
||||||
|
|
@ -1090,16 +1085,16 @@ func (s *Server) RegisterClient(client *Client) (uid uint32, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grumble can only register users with certificates.
|
// Grumble can only register users with certificates.
|
||||||
if len(client.CertHash) == 0 {
|
if client.HasCertificate() {
|
||||||
return 0, errors.New("no cert hash")
|
return 0, errors.New("no cert hash")
|
||||||
}
|
}
|
||||||
|
|
||||||
user.Email = client.Email
|
user.Email = client.Email
|
||||||
user.CertHash = client.CertHash
|
user.CertHash = client.CertHash()
|
||||||
|
|
||||||
uid = s.nextUserId
|
uid = s.nextUserId
|
||||||
s.Users[uid] = user
|
s.Users[uid] = user
|
||||||
s.UserCertMap[client.CertHash] = user
|
s.UserCertMap[client.CertHash()] = user
|
||||||
s.UserNameMap[client.Username] = user
|
s.UserNameMap[client.Username] = user
|
||||||
|
|
||||||
return uid, nil
|
return uid, nil
|
||||||
|
|
@ -1126,16 +1121,16 @@ func (s *Server) RemoveRegistration(uid uint32) (err error) {
|
||||||
// Remove references for user id uid from channel. Traverses subchannels.
|
// Remove references for user id uid from channel. Traverses subchannels.
|
||||||
func (s *Server) removeRegisteredUserFromChannel(uid uint32, channel *Channel) {
|
func (s *Server) removeRegisteredUserFromChannel(uid uint32, channel *Channel) {
|
||||||
|
|
||||||
newACL := []*ChannelACL{}
|
newACL := []acl.ACL{}
|
||||||
for _, chanacl := range channel.ACL {
|
for _, chanacl := range channel.ACL.ACLs {
|
||||||
if chanacl.UserId == int(uid) {
|
if chanacl.UserId == int(uid) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
newACL = append(newACL, chanacl)
|
newACL = append(newACL, chanacl)
|
||||||
}
|
}
|
||||||
channel.ACL = newACL
|
channel.ACL.ACLs = newACL
|
||||||
|
|
||||||
for _, grp := range channel.Groups {
|
for _, grp := range channel.ACL.Groups {
|
||||||
if _, ok := grp.Add[int(uid)]; ok {
|
if _, ok := grp.Add[int(uid)]; ok {
|
||||||
delete(grp.Add, int(uid))
|
delete(grp.Add, int(uid))
|
||||||
}
|
}
|
||||||
|
|
@ -1155,7 +1150,7 @@ func (s *Server) removeRegisteredUserFromChannel(uid uint32, channel *Channel) {
|
||||||
// Remove a channel
|
// Remove a channel
|
||||||
func (server *Server) RemoveChannel(channel *Channel) {
|
func (server *Server) RemoveChannel(channel *Channel) {
|
||||||
// Can't remove root
|
// Can't remove root
|
||||||
if channel.parent == nil {
|
if channel == server.RootChannel() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1172,12 +1167,12 @@ func (server *Server) RemoveChannel(channel *Channel) {
|
||||||
// Remove all clients
|
// Remove all clients
|
||||||
for _, client := range channel.clients {
|
for _, client := range channel.clients {
|
||||||
target := channel.parent
|
target := channel.parent
|
||||||
for target.parent != nil && !server.HasPermission(client, target, EnterPermission) {
|
for target.parent != nil && !acl.HasPermission(&target.ACL, client, acl.EnterPermission) {
|
||||||
target = target.parent
|
target = target.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
userstate := &mumbleproto.UserState{}
|
userstate := &mumbleproto.UserState{}
|
||||||
userstate.Session = proto.Uint32(client.Session)
|
userstate.Session = proto.Uint32(client.Session())
|
||||||
userstate.ChannelId = proto.Uint32(uint32(target.Id))
|
userstate.ChannelId = proto.Uint32(uint32(target.Id))
|
||||||
server.userEnterChannel(client, target, userstate)
|
server.userEnterChannel(client, target, userstate)
|
||||||
if err := server.broadcastProtoMessage(userstate); err != nil {
|
if err := server.broadcastProtoMessage(userstate); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import "mumbleapp.com/grumble/pkg/acl"
|
||||||
|
|
||||||
// A VoiceTarget holds information about a single
|
// A VoiceTarget holds information about a single
|
||||||
// VoiceTarget entry of a Client.
|
// VoiceTarget entry of a Client.
|
||||||
type VoiceTarget struct {
|
type VoiceTarget struct {
|
||||||
|
|
@ -72,9 +74,9 @@ func (vt *VoiceTarget) SendVoiceBroadcast(vb *VoiceBroadcast) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !vtc.subChannels && !vtc.links && vtc.onlyGroup == "" {
|
if !vtc.subChannels && !vtc.links && vtc.onlyGroup == "" {
|
||||||
if server.HasPermission(client, channel, WhisperPermission) {
|
if acl.HasPermission(&channel.ACL, client, acl.WhisperPermission) {
|
||||||
for _, target := range channel.clients {
|
for _, target := range channel.clients {
|
||||||
fromChannels[target.Session] = target
|
fromChannels[target.Session()] = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -92,10 +94,10 @@ func (vt *VoiceTarget) SendVoiceBroadcast(vb *VoiceBroadcast) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for _, newchan := range newchans {
|
for _, newchan := range newchans {
|
||||||
if server.HasPermission(client, newchan, WhisperPermission) {
|
if acl.HasPermission(&newchan.ACL, client, acl.WhisperPermission) {
|
||||||
for _, target := range newchan.clients {
|
for _, target := range newchan.clients {
|
||||||
if vtc.onlyGroup == "" || GroupMemberCheck(newchan, newchan, vtc.onlyGroup, target) {
|
if vtc.onlyGroup == "" || acl.GroupMemberCheck(&newchan.ACL, &newchan.ACL, vtc.onlyGroup, target) {
|
||||||
fromChannels[target.Session] = target
|
fromChannels[target.Session()] = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -106,15 +108,15 @@ func (vt *VoiceTarget) SendVoiceBroadcast(vb *VoiceBroadcast) {
|
||||||
for _, session := range vt.sessions {
|
for _, session := range vt.sessions {
|
||||||
target := server.clients[session]
|
target := server.clients[session]
|
||||||
if target != nil {
|
if target != nil {
|
||||||
if _, alreadyInFromChannels := fromChannels[target.Session]; !alreadyInFromChannels {
|
if _, alreadyInFromChannels := fromChannels[target.Session()]; !alreadyInFromChannels {
|
||||||
direct[target.Session] = target
|
direct[target.Session()] = target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we don't send to ourselves.
|
// Make sure we don't send to ourselves.
|
||||||
delete(direct, client.Session)
|
delete(direct, client.Session())
|
||||||
delete(fromChannels, client.Session)
|
delete(fromChannels, client.Session())
|
||||||
|
|
||||||
if vt.directCache == nil {
|
if vt.directCache == nil {
|
||||||
vt.directCache = direct
|
vt.directCache = direct
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue