Ejemplo n.º 1
0
// ACL set/query
func (server *Server) handleAclMessage(client *Client, msg *Message) {
	pacl := &mumbleproto.ACL{}
	err := proto.Unmarshal(msg.buf, pacl)
	if err != nil {
		client.Panic(err)
		return
	}

	// Look up the channel this ACL message operates on.
	channel, ok := server.Channels[int(*pacl.ChannelId)]
	if !ok {
		return
	}

	// Does the user have permission to update or look at ACLs?
	if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && !(channel.parent != nil && acl.HasPermission(&channel.parent.ACL, client, acl.WritePermission)) {
		client.sendPermissionDenied(client, channel, acl.WritePermission)
		return
	}

	reply := &mumbleproto.ACL{}
	reply.ChannelId = proto.Uint32(uint32(channel.Id))

	channels := []*Channel{}
	users := map[int]bool{}

	// Query the current ACL state for the channel
	if pacl.Query != nil && *pacl.Query != false {
		reply.InheritAcls = proto.Bool(channel.ACL.InheritACL)
		// Walk the channel tree to get all relevant channels.
		// (Stop if we reach a channel that doesn't have the InheritACL flag set)
		iter := channel
		for iter != nil {
			channels = append([]*Channel{iter}, channels...)
			if iter == channel || iter.ACL.InheritACL {
				iter = iter.parent
			} else {
				iter = nil
			}
		}

		// Construct the protobuf ChanACL objects corresponding to the ACLs defined
		// in our channel list.
		reply.Acls = []*mumbleproto.ACL_ChanACL{}
		for _, iter := range channels {
			for _, chanacl := range iter.ACL.ACLs {
				if iter == channel || chanacl.ApplySubs {
					mpacl := &mumbleproto.ACL_ChanACL{}
					mpacl.Inherited = proto.Bool(iter != channel)
					mpacl.ApplyHere = proto.Bool(chanacl.ApplyHere)
					mpacl.ApplySubs = proto.Bool(chanacl.ApplySubs)
					if chanacl.UserId >= 0 {
						mpacl.UserId = proto.Uint32(uint32(chanacl.UserId))
						users[chanacl.UserId] = true
					} else {
						mpacl.Group = proto.String(chanacl.Group)
					}
					mpacl.Grant = proto.Uint32(uint32(chanacl.Allow))
					mpacl.Deny = proto.Uint32(uint32(chanacl.Deny))
					reply.Acls = append(reply.Acls, mpacl)
				}
			}
		}

		parent := channel.parent
		allnames := channel.ACL.GroupNames()

		// 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.
		reply.Groups = []*mumbleproto.ACL_ChanGroup{}
		for _, name := range allnames {
			var (
				group     acl.Group
				hasgroup  bool
				pgroup    acl.Group
				haspgroup bool
			)

			group, hasgroup = channel.ACL.Groups[name]
			if parent != nil {
				pgroup, haspgroup = parent.ACL.Groups[name]
			}

			mpgroup := &mumbleproto.ACL_ChanGroup{}
			mpgroup.Name = proto.String(name)

			mpgroup.Inherit = proto.Bool(true)
			if hasgroup {
				mpgroup.Inherit = proto.Bool(group.Inherit)
			}

			mpgroup.Inheritable = proto.Bool(true)
			if hasgroup {
				mpgroup.Inheritable = proto.Bool(group.Inheritable)
			}

			mpgroup.Inherited = proto.Bool(haspgroup && pgroup.Inheritable)

			// 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
			// message that maps user ids to usernames.
			if hasgroup {
				toadd := map[int]bool{}
				for uid, _ := range group.Add {
					users[uid] = true
					toadd[uid] = true
				}
				for uid, _ := range group.Remove {
					users[uid] = true
					delete(toadd, uid)
				}
				for uid, _ := range toadd {
					mpgroup.Add = append(mpgroup.Add, uint32(uid))
				}
			}
			if haspgroup {
				for uid, _ := range pgroup.MembersInContext(&parent.ACL) {
					users[uid] = true
					mpgroup.InheritedMembers = append(mpgroup.InheritedMembers, uint32(uid))
				}
			}

			reply.Groups = append(reply.Groups, mpgroup)
		}

		if err := client.sendMessage(reply); err != nil {
			client.Panic(err)
			return
		}

		// Map the user ids in the user map to usernames of users.
		queryusers := &mumbleproto.QueryUsers{}
		for uid, _ := range users {
			user, ok := server.Users[uint32(uid)]
			if !ok {
				client.Printf("Invalid user id in ACL")
				continue
			}
			queryusers.Ids = append(queryusers.Ids, uint32(uid))
			queryusers.Names = append(queryusers.Names, user.Name)
		}
		if len(queryusers.Ids) > 0 {
			client.sendMessage(queryusers)
		}

		// Set new groups and ACLs
	} else {

		// Get old temporary members
		oldtmp := map[string]map[int]bool{}
		for name, grp := range channel.ACL.Groups {
			oldtmp[name] = grp.Temporary
		}

		// Clear current ACLs and groups
		channel.ACL.ACLs = []acl.ACL{}
		channel.ACL.Groups = map[string]acl.Group{}

		// Add the received groups to the channel.
		channel.ACL.InheritACL = *pacl.InheritAcls
		for _, pbgrp := range pacl.Groups {
			changroup := acl.EmptyGroupWithName(*pbgrp.Name)

			changroup.Inherit = *pbgrp.Inherit
			changroup.Inheritable = *pbgrp.Inheritable
			for _, uid := range pbgrp.Add {
				changroup.Add[int(uid)] = true
			}
			for _, uid := range pbgrp.Remove {
				changroup.Remove[int(uid)] = true
			}
			if temp, ok := oldtmp[*pbgrp.Name]; ok {
				changroup.Temporary = temp
			}

			channel.ACL.Groups[changroup.Name] = changroup
		}
		// Add the received ACLs to the channel.
		for _, pbacl := range pacl.Acls {
			chanacl := acl.ACL{}
			chanacl.ApplyHere = *pbacl.ApplyHere
			chanacl.ApplySubs = *pbacl.ApplySubs
			if pbacl.UserId != nil {
				chanacl.UserId = int(*pbacl.UserId)
			} else {
				chanacl.Group = *pbacl.Group
			}
			chanacl.Deny = acl.Permission(*pbacl.Deny & acl.AllPermissions)
			chanacl.Allow = acl.Permission(*pbacl.Grant & acl.AllPermissions)

			channel.ACL.ACLs = append(channel.ACL.ACLs, chanacl)
		}

		// Clear the Server's caches
		server.ClearCaches()

		// Regular user?
		if !acl.HasPermission(&channel.ACL, client, acl.WritePermission) && client.IsRegistered() || client.HasCertificate() {
			chanacl := acl.ACL{}
			chanacl.ApplyHere = true
			chanacl.ApplySubs = false
			if client.IsRegistered() {
				chanacl.UserId = client.UserId()
			} else if client.HasCertificate() {
				chanacl.Group = "$" + client.CertHash()
			}
			chanacl.Deny = acl.Permission(acl.NonePermission)
			chanacl.Allow = acl.Permission(acl.WritePermission | acl.TraversePermission)

			channel.ACL.ACLs = append(channel.ACL.ACLs, chanacl)

			server.ClearCaches()
		}

		// Update freezer
		server.UpdateFrozenChannelACLs(channel)
	}
}