This commit is contained in:
Ruben Seyer 2024-04-07 14:42:49 +02:00 committed by GitHub
commit a05dc7c8ff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 38 additions and 36 deletions

View file

@ -12,6 +12,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@ -262,7 +263,7 @@ func (c *Channel) Unfreeze(fc *freezer.Channel) {
if fgrp.Name == nil { if fgrp.Name == nil {
continue continue
} }
g := acl.Group{} g := acl.EmptyGroupWithName(fgrp.GetName())
if fgrp.Inherit != nil { if fgrp.Inherit != nil {
g.Inherit = *fgrp.Inherit g.Inherit = *fgrp.Inherit
} }
@ -483,7 +484,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
// Update the server's user maps to point correctly // Update the server's user maps to point correctly
// to the new user. // to the new user.
s.Users[u.Id] = u s.Users[u.Id] = u
s.UserNameMap[u.Name] = u s.UserNameMap[strings.ToLower(u.Name)] = u
if len(u.CertHash) > 0 { if len(u.CertHash) > 0 {
s.UserCertMap[u.CertHash] = u s.UserCertMap[u.CertHash] = u
} }
@ -553,7 +554,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
// Update the various user maps in the server to // Update the various user maps in the server to
// be able to correctly look up the user. // be able to correctly look up the user.
s.Users[user.Id] = user s.Users[user.Id] = user
s.UserNameMap[user.Name] = user s.UserNameMap[strings.ToLower(user.Name)] = user
if len(user.CertHash) > 0 { if len(user.CertHash) > 0 {
s.UserCertMap[user.CertHash] = user s.UserCertMap[user.CertHash] = user
} }
@ -574,7 +575,7 @@ func NewServerFromFrozen(name string) (s *Server, err error) {
if ok { if ok {
// Clear the server maps. That should do it. // Clear the server maps. That should do it.
delete(s.Users, userId) delete(s.Users, userId)
delete(s.UserNameMap, user.Name) delete(s.UserNameMap, strings.ToLower(user.Name))
if len(user.CertHash) > 0 { if len(user.CertHash) > 0 {
delete(s.UserCertMap, user.CertHash) delete(s.UserCertMap, user.CertHash)
} }

View file

@ -9,6 +9,7 @@ import (
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"net" "net"
"strings"
"time" "time"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto"
@ -1211,6 +1212,7 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
if pbacl.UserId != nil { if pbacl.UserId != nil {
chanacl.UserId = int(*pbacl.UserId) chanacl.UserId = int(*pbacl.UserId)
} else { } else {
chanacl.UserId = -1
chanacl.Group = *pbacl.Group chanacl.Group = *pbacl.Group
} }
chanacl.Deny = acl.Permission(*pbacl.Deny & acl.AllPermissions) chanacl.Deny = acl.Permission(*pbacl.Deny & acl.AllPermissions)
@ -1223,13 +1225,14 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
server.ClearCaches() server.ClearCaches()
// Regular user? // Regular user?
if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && client.IsRegistered() || client.HasCertificate() { if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && (client.IsRegistered() || client.HasCertificate()) {
chanacl := acl.ACL{} 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.UserId = -1
chanacl.Group = "$" + client.CertHash() chanacl.Group = "$" + client.CertHash()
} }
chanacl.Deny = acl.Permission(acl.NonePermission) chanacl.Deny = acl.Permission(acl.NonePermission)
@ -1267,7 +1270,7 @@ func (server *Server) handleQueryUsers(client *Client, msg *Message) {
} }
for _, name := range query.Names { for _, name := range query.Names {
user, exists := server.UserNameMap[name] user, exists := server.UserNameMap[strings.ToLower(name)]
if exists { if exists {
reply.Ids = append(reply.Ids, user.Id) reply.Ids = append(reply.Ids, user.Id)
reply.Names = append(reply.Names, name) reply.Names = append(reply.Names, name)

View file

@ -149,7 +149,7 @@ func NewServer(id int64) (s *Server, err error) {
s.UserCertMap = make(map[string]*User) s.UserCertMap = make(map[string]*User)
s.UserNameMap = make(map[string]*User) s.UserNameMap = make(map[string]*User)
s.Users[0], err = NewUser(0, "SuperUser") s.Users[0], err = NewUser(0, "SuperUser")
s.UserNameMap["SuperUser"] = s.Users[0] s.UserNameMap["superuser"] = s.Users[0]
s.nextUserId = 1 s.nextUserId = 1
s.Channels = make(map[int]*Channel) s.Channels = make(map[int]*Channel)
@ -508,7 +508,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
} else { } else {
if server.CheckSuperUserPassword(*auth.Password) { if server.CheckSuperUserPassword(*auth.Password) {
ok := false ok := false
client.user, ok = server.UserNameMap[client.Username] client.user, ok = server.UserNameMap[strings.ToLower(client.Username)]
if !ok { if !ok {
client.RejectAuth(mumbleproto.Reject_InvalidUsername, "") client.RejectAuth(mumbleproto.Reject_InvalidUsername, "")
return return
@ -520,7 +520,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
} }
} else { } else {
// First look up registration by name. // First look up registration by name.
user, exists := server.UserNameMap[client.Username] user, exists := server.UserNameMap[strings.ToLower(client.Username)]
if exists { if exists {
if client.HasCertificate() && user.CertHash == client.CertHash() { if client.HasCertificate() && user.CertHash == client.CertHash() {
client.user = user client.user = user
@ -689,12 +689,10 @@ func (server *Server) finishAuthenticate(client *Client) {
if client.IsSuperUser() { if client.IsSuperUser() {
sync.Permissions = proto.Uint64(uint64(acl.AllPermissions)) sync.Permissions = proto.Uint64(uint64(acl.AllPermissions))
} else { } else {
// fixme(mkrautz): previously we calculated the user's // todo: acl caching?
// permissions and sent them to the client in here. This // It might seem like we should send the permissions relative to the channel joined, but
// code relied on our ACL cache, but that has been temporarily // Murmur sends the root channel permissions, so we do the same
// thrown out because of our ACL handling code moving to its sync.Permissions = proto.Uint64(uint64(acl.EffectivePermission(&server.RootChannel().ACL, client)))
// own package.
sync.Permissions = nil
} }
if err := client.sendMessage(sync); err != nil { if err := client.sendMessage(sync); err != nil {
client.Panicf("%v", err) client.Panicf("%v", err)
@ -899,10 +897,8 @@ func (server *Server) sendClientPermissions(client *Client, channel *Channel) {
return return
} }
// fixme(mkrautz): re-add when we have ACL caching // todo: acl caching?
return perm := acl.EffectivePermission(&channel.ACL, client)
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)),
@ -1142,7 +1138,7 @@ func (s *Server) RegisterClient(client *Client) (uid uint32, err error) {
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[strings.ToLower(client.Username)] = user
return uid, nil return uid, nil
} }
@ -1157,7 +1153,7 @@ func (s *Server) RemoveRegistration(uid uint32) (err error) {
// Remove from user maps // Remove from user maps
delete(s.Users, uid) delete(s.Users, uid)
delete(s.UserCertMap, user.CertHash) delete(s.UserCertMap, user.CertHash)
delete(s.UserNameMap, user.Name) delete(s.UserNameMap, strings.ToLower(user.Name))
// Remove from groups and ACLs. // Remove from groups and ACLs.
s.removeRegisteredUserFromChannel(uid, s.RootChannel()) s.removeRegisteredUserFromChannel(uid, s.RootChannel())

View file

@ -61,7 +61,7 @@ type ACL struct {
// The ApplyHere flag determines whether the ACL // The ApplyHere flag determines whether the ACL
// should apply to the current channel. // should apply to the current channel.
ApplyHere bool ApplyHere bool
// The ApplySubs flag determines whethr the ACL // The ApplySubs flag determines whether the ACL
// should apply to subchannels. // should apply to subchannels.
ApplySubs bool ApplySubs bool
@ -87,17 +87,21 @@ func (acl *ACL) IsChannelACL() bool {
// HasPermission checks whether the given user has permission perm in the given context. // 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. // The permission perm must be a single permission and not a combination of permissions.
func HasPermission(ctx *Context, user User, perm Permission) bool { func HasPermission(ctx *Context, user User, perm Permission) bool {
// This test mirrors the Murmur behaviour. Unfortunately, this means that a combination of permissions
// results in an inclusive OR check i.e. if any one of the bits are set return true.
return (EffectivePermission(ctx, user) & perm) != NonePermission
}
// EffectivePermission returns the effective permission bits for a user in the given context.
func EffectivePermission(ctx *Context, user User) Permission {
// We can't check permissions on a nil ctx. // We can't check permissions on a nil ctx.
if ctx == nil { if ctx == nil {
panic("acl: HasPermission got nil context") panic("acl: EffectivePermission got nil context")
} }
// SuperUser can't speak or whisper, but everything else is OK // SuperUser can't speak or whisper, but everything else is OK
if user.UserId() == 0 { if user.UserId() == 0 {
if perm == SpeakPermission || perm == WhisperPermission { return Permission(AllPermissions &^ (SpeakPermission | WhisperPermission))
return false
}
return true
} }
// Default permissions // Default permissions
@ -116,13 +120,13 @@ func HasPermission(ctx *Context, user User, perm Permission) bool {
} }
// Iterate through ACLs that are defined on ctx. Note: this does not include // 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 // 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!) // iter with the same name, that modifies the permissions a bit!)
for _, acl := range ctx.ACLs { for _, acl := range ctx.ACLs {
// Determine whether the ACL applies to user. // Determine whether the ACL applies to user.
// If it is a user ACL and the user id of the ACL // If it is a user ACL and the user id of the ACL
// matches user's id, we're good to go. // matches user's id, we're good to go.
// //
// If it's a group ACL, we have to parse and interpret // If it is a group ACL, we have to parse and interpret
// the group string in the current context to determine // the group string in the current context to determine
// membership. For that we use GroupMemberCheck. // membership. For that we use GroupMemberCheck.
matchUser := acl.IsUserACL() && acl.UserId == user.UserId() matchUser := acl.IsUserACL() && acl.UserId == user.UserId()
@ -158,12 +162,10 @@ func HasPermission(ctx *Context, user User, perm Permission) bool {
// The +write permission implies all permissions except for +speak and +whisper. // 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 // This means that if the user has WritePermission, we should return true for all
// permissions exccept SpeakPermission and WhisperPermission. // permissions except SpeakPermission and WhisperPermission.
if perm != SpeakPermission && perm != WhisperPermission { if (granted & WritePermission) != NonePermission {
return (granted & (perm | WritePermission)) != NonePermission return granted | (AllPermissions &^ (SpeakPermission | WhisperPermission))
} else {
return (granted & perm) != NonePermission
} }
return false return granted
} }

View file

@ -344,7 +344,7 @@ func GroupMemberCheck(current *Context, acl *Context, name string, user User) (o
func (ctx *Context) GroupNames() []string { func (ctx *Context) GroupNames() []string {
names := map[string]bool{} names := map[string]bool{}
origCtx := ctx origCtx := ctx
contexts := []*Context{} contexts := buildChain(ctx)
// Walk through the whole context chain and all groups in it. // Walk through the whole context chain and all groups in it.
for _, ctx := range contexts { for _, ctx := range contexts {