diff --git a/client.go b/client.go index 57625cc..4b5262e 100644 --- a/client.go +++ b/client.go @@ -60,6 +60,7 @@ type Client struct { Username string Session uint32 CertHash string + Email string Tokens []string Channel *Channel SelfMute bool diff --git a/freeze.go b/freeze.go index cf37fb2..27d384a 100644 --- a/freeze.go +++ b/freeze.go @@ -292,6 +292,9 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) { u.LastActive = fu.LastActive s.Users[u.Id] = u + if u.Id > s.nextUserId { + s.nextUserId = u.Id + 1 + } s.UserNameMap[u.Name] = u if len(u.CertHash) > 0 { s.UserCertMap[u.CertHash] = u diff --git a/message.go b/message.go index 59a1f33..28650d3 100644 --- a/message.go +++ b/message.go @@ -601,21 +601,19 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) { if userstate.UserId != nil { // If user == actor, check for SelfRegisterPermission on root channel. // If user != actor, check for RegisterPermission permission on root channel. - permCheck := Permission(NonePermission) - uid := *userstate.UserId - if target == actor { - permCheck = SelfRegisterPermission - } else { - permCheck = RegisterPermission + perm := Permission(RegisterPermission) + if actor == target { + perm = Permission(SelfRegisterPermission) } - if uid >= 0 || !server.HasPermission(actor, server.root, SelfRegisterPermission) { - client.sendPermissionDenied(actor, server.root, permCheck) + + if target.IsRegistered() || !server.HasPermission(actor, server.root, perm) { + client.sendPermissionDenied(actor, server.root, perm) return } - // We can't register a user with an empty hash. if len(target.CertHash) == 0 { client.sendPermissionDeniedTypeUser("MissingCertificate", target) + return } } @@ -733,10 +731,17 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) { broadcast = true } + userRegistrationChanged := false if userstate.UserId != nil { - // fixme(mkrautz): Registration is currently unhandled. - log.Printf("handleUserState: (Self)Register not implemented yet!") - userstate.UserId = nil + uid := server.RegisterClient(client) + if uid > 0 { + userstate.UserId = proto.Uint32(uid) + client.user = server.Users[uid] + userRegistrationChanged = true + } else { + userstate.UserId = nil + } + broadcast = true } if userstate.ChannelId != nil { @@ -799,6 +804,10 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) { userstate.CommentHash = nil } + if userRegistrationChanged { + server.ClearACLCache() + } + err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool { return client.Version >= 0x10203 }) @@ -1198,3 +1207,55 @@ func (server *Server) handleRequestBlob(client *Client, msg *Message) { } } } + +// User list query, user rename, user de-register +func (server *Server) handleUserList(client *Client, msg *Message) { + userlist := &mumbleproto.UserList{} + err := proto.Unmarshal(msg.buf, userlist) + if err != nil { + client.Panic(err.String()) + return + } + + // Only users who are allowed to register other users can access the user list. + if !server.HasPermission(client, server.root, RegisterPermission) { + client.sendPermissionDenied(client, server.root, RegisterPermission) + return + } + + // Query user list + if len(userlist.Users) == 0 { + for uid, user := range server.Users { + if uid == 0 { + continue + } + userlist.Users = append(userlist.Users, &mumbleproto.UserList_User{ + UserId: proto.Uint32(uid), + Name: proto.String(user.Name), + }) + } + if err := client.sendProtoMessage(MessageUserList, userlist); err != nil { + client.Panic(err.String()) + return + } + // Rename, registration removal + } else { + for _, listUser := range userlist.Users { + uid := *listUser.UserId + if uid == 0 { + continue + } + // De-register a user + if listUser.Name == nil { + server.RemoveRegistration(uid) + // Rename user + } else { + // todo(mkrautz): Validate name. + user, ok := server.Users[uid] + if ok { + user.Name = *listUser.Name + } + } + } + } +} diff --git a/server.go b/server.go index 00fa861..8caceb1 100644 --- a/server.go +++ b/server.go @@ -84,6 +84,7 @@ type Server struct { Users map[uint32]*User UserCertMap map[string]*User UserNameMap map[string]*User + nextUserId uint32 // ACL cache aclcache ACLCache @@ -537,6 +538,11 @@ func (server *Server) finishAuthenticate(client *Client) { Name: proto.String(client.ShownName()), ChannelId: proto.Uint32(0), } + + if len(client.CertHash) > 0 { + userstate.Hash = proto.String(client.CertHash) + } + if client.IsRegistered() { userstate.UserId = proto.Uint32(uint32(client.UserId())) @@ -681,6 +687,10 @@ func (server *Server) sendUserList(client *Client) { ChannelId: proto.Uint32(uint32(connectedClient.Channel.Id)), } + if len(connectedClient.CertHash) > 0 { + userstate.Hash = connectedClient.CertHash + } + if connectedClient.IsRegistered() { userstate.UserId = proto.Uint32(uint32(connectedClient.UserId())) @@ -709,10 +719,6 @@ func (server *Server) sendUserList(client *Client) { userstate.Comment = proto.String(string(buf)) } } - - if len(connectedClient.user.CertHash) > 0 { - userstate.Hash = proto.String(connectedClient.user.CertHash) - } } if connectedClient.Mute { @@ -820,7 +826,7 @@ func (server *Server) handleIncomingMessage(client *Client, msg *Message) { case MessageContextAction: log.Printf("MessageContextAction from client") case MessageUserList: - log.Printf("MessageUserList from client") + server.handleUserList(msg.client, msg) case MessageVoiceTarget: log.Printf("MessageVoiceTarget from client") case MessagePermissionQuery: @@ -1003,6 +1009,48 @@ func (s *Server) FreezeServer() io.ReadCloser { return fr.readCloser } +// Register a client on the server. +func (s *Server) RegisterClient(client *Client) (uid uint32) { + // Increment nextUserId only if registration succeeded. + defer func() { + if uid > 0 { + s.nextUserId += 1 + } + }() + + user, err := NewUser(s.nextUserId, client.Username) + if err != nil { + return 0 + } + + // Grumble can only register users with certificates. + if len(client.CertHash) == 0 { + return 0 + } + + user.Email = client.Email + user.CertHash = client.CertHash + + uid = s.nextUserId + s.Users[uid] = user + s.UserCertMap[client.CertHash] = user + s.UserNameMap[client.Username] = user + return uid +} + +// Remove a registered user. +func (s *Server) RemoveRegistration(uid uint32) (err os.Error) { + user, ok := s.Users[uid] + if !ok { + return os.NewError("Unknown user ID") + } + + s.Users[uid] = nil, false + s.UserCertMap[user.CertHash] = nil, false + s.UserNameMap[user.Name] = nil, false + return nil +} + // The accept loop of the server. func (s *Server) ListenAndMurmur() { // Launch the event handler goroutine