Recognize registered users by their certificate hash.

This commit is contained in:
Mikkel Krautz 2011-04-09 21:34:02 +02:00
parent 9036cd64af
commit 58fca6bcf7
9 changed files with 215 additions and 164 deletions

4
acl.go
View file

@ -143,7 +143,7 @@ func NewChannelACL(channel *Channel) *ChannelACL {
// and not a combination of permissions. // and not a combination of permissions.
func (server *Server) HasPermission(client *Client, channel *Channel, perm Permission) bool { func (server *Server) HasPermission(client *Client, channel *Channel, perm Permission) bool {
// SuperUser can't speak or whisper, but everything else is OK // SuperUser can't speak or whisper, but everything else is OK
if client.UserId == 0 { if client.IsSuperUser() {
if perm == SpeakPermission || perm == WhisperPermission { if perm == SpeakPermission || perm == WhisperPermission {
return false return false
} }
@ -193,7 +193,7 @@ func (server *Server) HasPermission(client *Client, channel *Channel, perm Permi
// //
// If it's a group ACL, we have to parse and interpret the group string in the // 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. // current context to determine membership. For that we use GroupMemberCheck.
matchUser := acl.IsUserACL() && acl.UserId == client.UserId matchUser := acl.IsUserACL() && acl.UserId == client.UserId()
matchGroup := GroupMemberCheck(channel, iter, acl.Group, client) matchGroup := GroupMemberCheck(channel, iter, acl.Group, client)
if matchUser || matchGroup { if matchUser || matchGroup {
if acl.Allow.IsSet(TraversePermission) { if acl.Allow.IsSet(TraversePermission) {

View file

@ -37,6 +37,15 @@ type Client struct {
codecs []int32 codecs []int32
udp bool udp bool
// If the client is a registered user on the server,
// the user field will point to the registration record.
user *User
// If the client has SuperUser privileges, superUser will be true.
// Note that Grumble doesn't store credentials of the SuperUser in
// the user data store, so we have to keep track of it separately.
superUser bool
// Version // Version
Version uint32 Version uint32
ClientName string ClientName string
@ -50,10 +59,9 @@ type Client struct {
TextureHash []byte TextureHash []byte
// Personal // Personal
UserId int
Session uint32
Username string Username string
Hash string Session uint32
CertHash string
Tokens []string Tokens []string
Channel *Channel Channel *Channel
SelfMute bool SelfMute bool
@ -67,6 +75,40 @@ type Client struct {
PluginIdentity string PluginIdentity string
} }
// Is the client a registered user?
func (client *Client) IsRegistered() bool {
return client.user != nil || client.IsSuperUser()
}
// Does the client have a certificate?
func (client *Client) HasCertificate() bool {
return len(client.CertHash) > 0
}
// Is the client the SuperUser?
func (client *Client) IsSuperUser() bool {
return client.superUser
}
// Get the User ID of this client.
// Returns -1 if the client is not a registered user.
func (client *Client) UserId() int {
if client.user == nil {
return -1
} else if client.superUser {
return 0
}
return int(client.user.Id)
}
// Get the client's shown name.
func (client *Client) ShownName() string {
if client.IsRegistered() {
return client.user.Name
}
return client.Username
}
// Something invalid happened on the wire. // Something invalid happened on the wire.
func (client *Client) Panic(reason string) { func (client *Client) Panic(reason string) {
log.Printf("Client panic: %s", reason) log.Printf("Client panic: %s", reason)

View file

@ -182,7 +182,7 @@ func NewServerFromFrozen(filename string) (s *Server, err os.Error) {
decoder := gob.NewDecoder(zr) decoder := gob.NewDecoder(zr)
decoder.Decode(&fs) decoder.Decode(&fs)
s, err = NewServer(int64(fs.Id), "", int(DefaultPort+fs.Id-1)) s, err = NewServer(int64(fs.Id), "0.0.0.0", int(DefaultPort+fs.Id-1))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -198,7 +198,7 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
// 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.
} else if name == "auth" { } else if name == "auth" {
member = client.UserId >= 0 member = client.IsRegistered()
// 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). // via a strong certificate (i.e. non-self-signed).
} else if name == "strong" { } else if name == "strong" {
@ -329,10 +329,10 @@ func GroupMemberCheck(current *Channel, aclchan *Channel, name string, client *C
} }
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(client.UserId()) || group.TemporaryContains(client.UserId()) || group.TemporaryContains(-int(client.Session)) {
member = true member = true
} }
if group.RemoveContains(client.UserId) { if group.RemoveContains(client.UserId()) {
member = false member = false
} }
} }

View file

@ -100,7 +100,6 @@ func main() {
} }
log.Printf("Using blob directory: %s", *blobdir) log.Printf("Using blob directory: %s", *blobdir)
// Should we import data from a Murmur SQLite file? // Should we import data from a Murmur SQLite file?
if len(*sqlitedb) > 0 { if len(*sqlitedb) > 0 {
f, err := os.Open(*datadir) f, err := os.Open(*datadir)

View file

@ -223,7 +223,7 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
} }
// Only registered users can create channels. // Only registered users can create channels.
if client.UserId < 0 && len(client.Hash) == 0 { if !client.IsRegistered() && !client.HasCertificate() {
client.sendPermissionDeniedTypeUser("MissingCertificate", client) client.sendPermissionDeniedTypeUser("MissingCertificate", client)
return return
} }
@ -251,9 +251,9 @@ 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.UserId >= 0 { if client.IsRegistered() {
grp := NewGroup(channel, "admin") grp := NewGroup(channel, "admin")
grp.Add[client.UserId] = true grp.Add[client.UserId()] = true
channel.Groups["admin"] = grp channel.Groups["admin"] = grp
} }
@ -263,10 +263,10 @@ func (server *Server) handleChannelStateMessage(client *Client, msg *Message) {
acl := NewChannelACL(channel) acl := NewChannelACL(channel)
acl.ApplyHere = true acl.ApplyHere = true
acl.ApplySubs = true acl.ApplySubs = true
if client.UserId >= 0 { if client.IsRegistered() {
acl.UserId = client.UserId acl.UserId = client.UserId()
} else { } else {
acl.Group = "$" + client.Hash acl.Group = "$" + client.CertHash
} }
acl.Deny = Permission(NonePermission) acl.Deny = Permission(NonePermission)
acl.Allow = Permission(WritePermission | TraversePermission) acl.Allow = Permission(WritePermission | TraversePermission)
@ -464,8 +464,8 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
client.Panic(err.String()) client.Panic(err.String())
} }
// Get the user to be removed. // Get the client to be removed.
user, ok := server.clients[*userremove.Session] removeClient, ok := server.clients[*userremove.Session]
if !ok { if !ok {
client.Panic("Invalid session in UserRemove message") client.Panic("Invalid session in UserRemove message")
return return
@ -476,12 +476,13 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
ban = *userremove.Ban ban = *userremove.Ban
} }
// Check user's permissions // Check client's permissions
perm := Permission(KickPermission) perm := Permission(KickPermission)
if ban { if ban {
perm = Permission(BanPermission) perm = Permission(BanPermission)
} }
if user.UserId == 0 || !server.HasPermission(client, server.root, perm) {
if removeClient.IsSuperUser() || !server.HasPermission(client, server.root, perm) {
client.sendPermissionDenied(client, server.root, perm) client.sendPermissionDenied(client, server.root, perm)
return return
} }
@ -497,7 +498,7 @@ func (server *Server) handleUserRemoveMessage(client *Client, msg *Message) {
return return
} }
user.ForceDisconnect() removeClient.ForceDisconnect()
} }
// Handle user state changes // Handle user state changes
@ -513,16 +514,16 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
log.Panic("Client not found in server's client map.") log.Panic("Client not found in server's client map.")
return return
} }
user := actor target := actor
if userstate.Session != nil { if userstate.Session != nil {
user, ok = server.clients[*userstate.Session] target, ok = server.clients[*userstate.Session]
if !ok { if !ok {
client.Panic("Invalid session in UserState message") client.Panic("Invalid session in UserState message")
return return
} }
} }
userstate.Session = proto.Uint32(user.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?
@ -535,15 +536,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 != user && !server.HasPermission(actor, user.Channel, MovePermission) { if actor != target && !server.HasPermission(actor, target.Channel, MovePermission) {
client.sendPermissionDenied(actor, user.Channel, MovePermission) client.sendPermissionDenied(actor, target.Channel, 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(user, dstChan, EnterPermission) { if !server.HasPermission(actor, dstChan, MovePermission) && !server.HasPermission(target, dstChan, EnterPermission) {
client.sendPermissionDenied(user, dstChan, EnterPermission) client.sendPermissionDenied(target, dstChan, EnterPermission)
return return
} }
@ -552,20 +553,20 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil { if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil {
// Disallow for SuperUser // Disallow for SuperUser
if user.UserId == 0 { if target.IsSuperUser() {
client.sendPermissionDeniedType("SuperUser") client.sendPermissionDeniedType("SuperUser")
return return
} }
// 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, user.Channel, MuteDeafenPermission) { if !server.HasPermission(actor, target.Channel, MuteDeafenPermission) {
client.sendPermissionDenied(actor, user.Channel, MuteDeafenPermission) client.sendPermissionDenied(actor, target.Channel, 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, user.Channel, MuteDeafenPermission) client.sendPermissionDenied(actor, target.Channel, MuteDeafenPermission)
return return
} }
} }
@ -575,7 +576,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
comment := *userstate.Comment comment := *userstate.Comment
// Clearing another user's comment. // Clearing another user's comment.
if user != 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.root, MovePermission) { if !server.HasPermission(actor, server.root, MovePermission) {
@ -594,7 +595,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
// Only set the comment if it is different from the current // Only set the comment if it is different from the current
// user comment. // user comment.
if comment == user.Comment { if comment == target.Comment {
userstate.Comment = nil userstate.Comment = nil
} }
} }
@ -610,7 +611,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
// If user != actor, check for RegisterPermission permission on root channel. // If user != actor, check for RegisterPermission permission on root channel.
permCheck := Permission(NonePermission) permCheck := Permission(NonePermission)
uid := *userstate.UserId uid := *userstate.UserId
if user == actor { if target == actor {
permCheck = SelfRegisterPermission permCheck = SelfRegisterPermission
} else { } else {
permCheck = RegisterPermission permCheck = RegisterPermission
@ -621,8 +622,8 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
} }
// We can't register a user with an empty hash. // We can't register a user with an empty hash.
if len(user.Hash) == 0 { if len(target.CertHash) == 0 {
client.sendPermissionDeniedTypeUser("MissingCertificate", user) client.sendPermissionDeniedTypeUser("MissingCertificate", target)
} }
} }
@ -635,7 +636,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
// - PluginContext // - PluginContext
// - PluginIdentity // - PluginIdentity
// - Recording // - Recording
if actor != user && (userstate.SelfDeaf != nil || userstate.SelfMute != nil || if actor != target && (userstate.SelfDeaf != nil || userstate.SelfMute != nil ||
userstate.Texture != nil || userstate.PluginContext != nil || userstate.PluginIdentity != nil || userstate.Texture != nil || userstate.PluginContext != nil || userstate.PluginIdentity != nil ||
userstate.Recording != nil) { userstate.Recording != nil) {
client.Panic("Invalid UserState") client.Panic("Invalid UserState")
@ -645,86 +646,86 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
broadcast := false broadcast := false
if userstate.Texture != nil { if userstate.Texture != nil {
user.Texture = userstate.Texture target.Texture = userstate.Texture
if len(user.Texture) >= 128 { if len(target.Texture) >= 128 {
hash := sha1.New() hash := sha1.New()
hash.Write(user.Texture) hash.Write(target.Texture)
user.TextureHash = hash.Sum() target.TextureHash = hash.Sum()
} else { } else {
user.TextureHash = []byte{} target.TextureHash = []byte{}
} }
broadcast = true broadcast = true
} }
if userstate.SelfDeaf != nil { if userstate.SelfDeaf != nil {
user.SelfDeaf = *userstate.SelfDeaf target.SelfDeaf = *userstate.SelfDeaf
if user.SelfDeaf { if target.SelfDeaf {
userstate.SelfDeaf = proto.Bool(true) userstate.SelfDeaf = proto.Bool(true)
user.SelfMute = true target.SelfMute = true
} }
broadcast = true broadcast = true
} }
if userstate.SelfMute != nil { if userstate.SelfMute != nil {
user.SelfMute = *userstate.SelfMute target.SelfMute = *userstate.SelfMute
if !user.SelfMute { if !target.SelfMute {
userstate.SelfDeaf = proto.Bool(false) userstate.SelfDeaf = proto.Bool(false)
user.SelfDeaf = false target.SelfDeaf = false
} }
} }
if userstate.PluginContext != nil { if userstate.PluginContext != nil {
user.PluginContext = userstate.PluginContext target.PluginContext = userstate.PluginContext
} }
if userstate.PluginIdentity != nil { if userstate.PluginIdentity != nil {
user.PluginIdentity = *userstate.PluginIdentity target.PluginIdentity = *userstate.PluginIdentity
} }
if userstate.Comment != nil { if userstate.Comment != nil {
user.Comment = *userstate.Comment target.Comment = *userstate.Comment
if len(user.Comment) >= 128 { if len(target.Comment) >= 128 {
hash := sha1.New() hash := sha1.New()
hash.Write([]byte(user.Comment)) hash.Write([]byte(target.Comment))
user.CommentHash = hash.Sum() target.CommentHash = hash.Sum()
} else { } else {
user.CommentHash = []byte{} target.CommentHash = []byte{}
} }
broadcast = true broadcast = true
} }
if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil { if userstate.Mute != nil || userstate.Deaf != nil || userstate.Suppress != nil || userstate.PrioritySpeaker != nil {
if userstate.Deaf != nil { if userstate.Deaf != nil {
user.Deaf = *userstate.Deaf target.Deaf = *userstate.Deaf
if user.Deaf { if target.Deaf {
userstate.Mute = proto.Bool(true) userstate.Mute = proto.Bool(true)
} }
} }
if userstate.Mute != nil { if userstate.Mute != nil {
user.Mute = *userstate.Mute target.Mute = *userstate.Mute
if !user.Mute { if !target.Mute {
userstate.Deaf = proto.Bool(false) userstate.Deaf = proto.Bool(false)
user.Deaf = false target.Deaf = false
} }
} }
if userstate.Suppress != nil { if userstate.Suppress != nil {
user.Suppress = *userstate.Suppress target.Suppress = *userstate.Suppress
} }
if userstate.PrioritySpeaker != nil { if userstate.PrioritySpeaker != nil {
user.PrioritySpeaker = *userstate.PrioritySpeaker target.PrioritySpeaker = *userstate.PrioritySpeaker
} }
broadcast = true broadcast = true
} }
if userstate.Recording != nil && *userstate.Recording != user.Recording { if userstate.Recording != nil && *userstate.Recording != target.Recording {
user.Recording = *userstate.Recording target.Recording = *userstate.Recording
txtmsg := &mumbleproto.TextMessage{} txtmsg := &mumbleproto.TextMessage{}
txtmsg.TreeId = append(txtmsg.TreeId, uint32(0)) txtmsg.TreeId = append(txtmsg.TreeId, uint32(0))
if user.Recording { if target.Recording {
txtmsg.Message = proto.String(fmt.Sprintf("User '%s' started recording", user.Username)) txtmsg.Message = proto.String(fmt.Sprintf("User '%s' started recording", target.Username))
} else { } else {
txtmsg.Message = proto.String(fmt.Sprintf("User '%s' stopped recording", user.Username)) txtmsg.Message = proto.String(fmt.Sprintf("User '%s' stopped recording", target.Username))
} }
server.broadcastProtoMessageWithPredicate(MessageTextMessage, txtmsg, func(client *Client) bool { server.broadcastProtoMessageWithPredicate(MessageTextMessage, txtmsg, func(client *Client) bool {
@ -743,7 +744,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
if userstate.ChannelId != nil { if userstate.ChannelId != nil {
channel, ok := server.Channels[int(*userstate.ChannelId)] channel, ok := server.Channels[int(*userstate.ChannelId)]
if ok { if ok {
server.userEnterChannel(user, channel, userstate) server.userEnterChannel(target, channel, userstate)
broadcast = true broadcast = true
} }
} }
@ -754,10 +755,10 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
// textures that were sent over the wire. We can use this to determine // textures that were sent over the wire. We can use this to determine
// whether a texture is a "new style" or an "old style" texture. // whether a texture is a "new style" or an "old style" texture.
texlen := uint32(0) texlen := uint32(0)
if user.Texture != nil && len(user.Texture) > 4 { if target.Texture != nil && len(target.Texture) > 4 {
texlen = uint32(user.Texture[0])<<24 | uint32(user.Texture[1])<<16 | uint32(user.Texture[2])<<8 | uint32(user.Texture[3]) texlen = uint32(target.Texture[0])<<24 | uint32(target.Texture[1])<<16 | uint32(target.Texture[2])<<8 | uint32(target.Texture[3])
} }
if userstate.Texture != nil && len(user.Texture) > 4 && texlen != 600*60*4 { if userstate.Texture != nil && len(target.Texture) > 4 && texlen != 600*60*4 {
// The sent texture is a new-style texture. Strip it from the message // The sent texture is a new-style texture. Strip it from the message
// we send to pre-1.2.2 clients. // we send to pre-1.2.2 clients.
userstate.Texture = nil userstate.Texture = nil
@ -768,7 +769,7 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
log.Panic("Unable to broadcast UserState") log.Panic("Unable to broadcast UserState")
} }
// Re-add it to the message, so that 1.2.2+ clients *do* get the new-style texture. // Re-add it to the message, so that 1.2.2+ clients *do* get the new-style texture.
userstate.Texture = user.Texture userstate.Texture = target.Texture
} else { } else {
// Old style texture. We can send the message as-is. // Old style texture. We can send the message as-is.
err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool { err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool {
@ -782,14 +783,14 @@ func (server *Server) handleUserStateMessage(client *Client, msg *Message) {
// If a texture hash is set on user, we transmit that instead of // If a texture hash is set on user, we transmit that instead of
// the texture itself. This allows the client to intelligently fetch // the texture itself. This allows the client to intelligently fetch
// the blobs that it does not already have in its local storage. // the blobs that it does not already have in its local storage.
if userstate != nil && len(user.TextureHash) > 0 { if userstate != nil && len(target.TextureHash) > 0 {
userstate.Texture = nil userstate.Texture = nil
userstate.TextureHash = user.TextureHash userstate.TextureHash = target.TextureHash
} }
// Ditto for comments. // Ditto for comments.
if userstate.Comment != nil && len(user.CommentHash) > 0 { if userstate.Comment != nil && len(target.CommentHash) > 0 {
userstate.Comment = nil userstate.Comment = nil
userstate.CommentHash = user.CommentHash userstate.CommentHash = target.CommentHash
} }
err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool { err := server.broadcastProtoMessageWithPredicate(MessageUserState, userstate, func(client *Client) bool {
@ -816,7 +817,7 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
// fixme(mkrautz): Check text message length. // fixme(mkrautz): Check text message length.
// fixme(mkrautz): Sanitize text as well. // fixme(mkrautz): Sanitize text as well.
users := make(map[uint32]*Client) clients := make(map[uint32]*Client)
// Tree // Tree
for _, chanid := range txtmsg.TreeId { for _, chanid := range txtmsg.TreeId {
@ -824,8 +825,8 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
if !server.HasPermission(client, channel, TextMessagePermission) { if !server.HasPermission(client, channel, TextMessagePermission) {
client.sendPermissionDenied(client, channel, TextMessagePermission) client.sendPermissionDenied(client, channel, TextMessagePermission)
} }
for _, user := range channel.clients { for _, target := range channel.clients {
users[user.Session] = user clients[target.Session] = target
} }
} }
} }
@ -837,28 +838,28 @@ func (server *Server) handleTextMessage(client *Client, msg *Message) {
client.sendPermissionDenied(client, channel, TextMessagePermission) client.sendPermissionDenied(client, channel, TextMessagePermission)
return return
} }
for _, user := range channel.clients { for _, target := range channel.clients {
users[user.Session] = user clients[target.Session] = target
} }
} }
} }
// Direct-to-users // Direct-to-clients
for _, session := range txtmsg.Session { for _, session := range txtmsg.Session {
if user, ok := server.clients[session]; ok { if target, ok := server.clients[session]; ok {
if !server.HasPermission(client, user.Channel, TextMessagePermission) { if !server.HasPermission(client, target.Channel, TextMessagePermission) {
client.sendPermissionDenied(client, user.Channel, TextMessagePermission) client.sendPermissionDenied(client, target.Channel, TextMessagePermission)
return return
} }
users[session] = user clients[session] = target
} }
} }
// Remove ourselves // Remove ourselves
users[client.Session] = nil, false clients[client.Session] = nil, false
for _, user := range users { for _, target := range clients {
user.sendProtoMessage(MessageTextMessage, &mumbleproto.TextMessage{ target.sendProtoMessage(MessageTextMessage, &mumbleproto.TextMessage{
Actor: proto.Uint32(client.Session), Actor: proto.Uint32(client.Session),
Message: txtmsg.Message, Message: txtmsg.Message,
}) })
@ -1052,17 +1053,16 @@ func (server *Server) handleAclMessage(client *Client, msg *Message) {
server.ClearACLCache() server.ClearACLCache()
// Regular user? // Regular user?
if !server.HasPermission(client, channel, WritePermission) && (client.UserId >= 0 || len(client.Hash) > 0) { if !server.HasPermission(client, channel, WritePermission) && client.IsRegistered() || client.HasCertificate() {
chanacl := NewChannelACL(channel) chanacl := NewChannelACL(channel)
chanacl.ApplyHere = true chanacl.ApplyHere = true
chanacl.ApplySubs = false chanacl.ApplySubs = false
if client.UserId >= 0 { if client.IsRegistered() {
chanacl.UserId = client.UserId chanacl.UserId = client.UserId()
} else { } else if client.HasCertificate() {
chanacl.Group = "$" + client.Hash chanacl.Group = "$" + client.CertHash
} }
chanacl.UserId = client.UserId
chanacl.Deny = Permission(NonePermission) chanacl.Deny = Permission(NonePermission)
chanacl.Allow = Permission(WritePermission | TraversePermission) chanacl.Allow = Permission(WritePermission | TraversePermission)
@ -1121,11 +1121,11 @@ func (server *Server) handleRequestBlob(client *Client, msg *Message) {
// Request for user textures // Request for user textures
if len(blobreq.SessionTexture) > 0 { if len(blobreq.SessionTexture) > 0 {
for _, sid := range blobreq.SessionTexture { for _, sid := range blobreq.SessionTexture {
if user, ok := server.clients[sid]; ok { if target, ok := server.clients[sid]; ok {
if len(user.Texture) > 0 { if len(target.Texture) > 0 {
userstate.Reset() userstate.Reset()
userstate.Session = proto.Uint32(uint32(user.Session)) userstate.Session = proto.Uint32(uint32(target.Session))
userstate.Texture = user.Texture userstate.Texture = target.Texture
if err := client.sendProtoMessage(MessageUserState, userstate); err != nil { if err := client.sendProtoMessage(MessageUserState, userstate); err != nil {
client.Panic(err.String()) client.Panic(err.String())
return return
@ -1138,11 +1138,11 @@ func (server *Server) handleRequestBlob(client *Client, msg *Message) {
// Request for user comments // Request for user comments
if len(blobreq.SessionComment) > 0 { if len(blobreq.SessionComment) > 0 {
for _, sid := range blobreq.SessionComment { for _, sid := range blobreq.SessionComment {
if user, ok := server.clients[sid]; ok { if target, ok := server.clients[sid]; ok {
if len(user.Comment) > 0 { if len(target.Comment) > 0 {
userstate.Reset() userstate.Reset()
userstate.Session = proto.Uint32(uint32(user.Session)) userstate.Session = proto.Uint32(uint32(target.Session))
userstate.Comment = proto.String(user.Comment) userstate.Comment = proto.String(target.Comment)
if err := client.sendProtoMessage(MessageUserState, userstate); err != nil { if err := client.sendProtoMessage(MessageUserState, userstate); err != nil {
client.Panic(err.String()) client.Panic(err.String())
return return

View file

@ -31,7 +31,7 @@ const (
// Create a new Server from a Murmur SQLite database // Create a new Server from a Murmur SQLite database
func NewServerFromSQLite(id int64, db *sqlite.Conn) (s *Server, err os.Error) { func NewServerFromSQLite(id int64, db *sqlite.Conn) (s *Server, err os.Error) {
s, err = NewServer(id, "", int(DefaultPort + id - 1)) s, err = NewServer(id, "", int(DefaultPort+id-1))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -355,7 +355,7 @@ func populateUsers(server *Server, db *sqlite.Conn) (err os.Error) {
case UserInfoComment: case UserInfoComment:
// unhandled // unhandled
case UserInfoHash: case UserInfoHash:
user.CertHash = "sha1-" + Value user.CertHash = Value
case UserInfoLastActive: case UserInfoLastActive:
// not a kv-pair (trigger) // not a kv-pair (trigger)
case UserInfoPassword: case UserInfoPassword:
@ -366,7 +366,5 @@ func populateUsers(server *Server, db *sqlite.Conn) (err os.Error) {
} }
} }
return return
} }

View file

@ -104,16 +104,7 @@ func NewServer(id int64, addr string, port int) (s *Server, err os.Error) {
s.MaxUsers = 10 s.MaxUsers = 10
s.Channels = make(map[int]*Channel) s.Channels = make(map[int]*Channel)
s.root = s.NewChannel(0, "Root") s.root = s.NewChannel(0, "Root")
/*
err = s.addChannelsFromDB(0)
if err != nil {
return nil, err
}
*/
s.aclcache = NewACLCache() s.aclcache = NewACLCache()
return return
@ -174,7 +165,7 @@ func (server *Server) NewClient(conn net.Conn) (err os.Error) {
client.msgchan = make(chan *Message) client.msgchan = make(chan *Message)
client.udprecv = make(chan []byte) client.udprecv = make(chan []byte)
client.UserId = -1 client.user = nil
go client.receiver() go client.receiver()
go client.udpreceiver() go client.udpreceiver()
@ -334,10 +325,47 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
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)
client.Hash = hex.EncodeToString(hash.Sum()) sum := hash.Sum()
client.CertHash = hex.EncodeToString(sum)
} }
log.Printf("hash=%s", client.Hash) if client.Username == "SuperUser" {
if auth.Password == nil {
client.RejectAuth("WrongUserPW", "")
return
} else {
if server.CheckSuperUserPassword(*auth.Password) {
client.superUser = true
} else {
client.RejectAuth("WrongUserPW", "")
return
}
}
} else {
// First look up registration by name.
user, exists := server.UserNameMap[client.Username]
if exists {
if user.CertHash == client.CertHash {
client.user = user
} else {
client.Panic("Invalid cert hash for user")
return
}
}
// Name matching didn't do. Try matching by certificate.
if client.user == nil {
user, exists := server.UserCertMap[client.CertHash]
if exists {
client.user = user
}
}
// Found a user for this guy
if client.user != nil {
log.Printf("Client authenticated as %v", client.user.Name)
}
}
// Setup the cryptstate for the client. // Setup the cryptstate for the client.
client.crypt, err = cryptstate.New() client.crypt, err = cryptstate.New()
@ -383,29 +411,13 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
server.hclients[host] = append(server.hclients[host], client) server.hclients[host] = append(server.hclients[host], client)
server.hmutex.Unlock() server.hmutex.Unlock()
// SuperUser login check
if client.Username == "SuperUser" {
// No password specified
if auth.Password == nil {
client.RejectAuth("WrongUserPW", "")
return
} else {
if server.CheckSuperUserPassword(*auth.Password) {
client.UserId = 0
} else {
client.RejectAuth("WrongUserPW", "")
return
}
}
}
userstate := &mumbleproto.UserState{ userstate := &mumbleproto.UserState{
Session: proto.Uint32(client.Session), Session: proto.Uint32(client.Session),
Name: proto.String(client.Username), Name: proto.String(client.Username),
ChannelId: proto.Uint32(0), ChannelId: proto.Uint32(0),
} }
if client.UserId >= 0 { if client.IsRegistered() {
userstate.UserId = proto.Uint32(uint32(client.UserId)) userstate.UserId = proto.Uint32(uint32(client.UserId()))
} }
server.userEnterChannel(client, server.root, userstate) server.userEnterChannel(client, server.root, userstate)
if err := server.broadcastProtoMessage(MessageUserState, userstate); err != nil { if err := server.broadcastProtoMessage(MessageUserState, userstate); err != nil {
@ -417,7 +429,7 @@ func (server *Server) handleAuthenticate(client *Client, msg *Message) {
sync := &mumbleproto.ServerSync{} sync := &mumbleproto.ServerSync{}
sync.Session = proto.Uint32(client.Session) sync.Session = proto.Uint32(client.Session)
sync.MaxBandwidth = proto.Uint32(server.MaxBandwidth) sync.MaxBandwidth = proto.Uint32(server.MaxBandwidth)
if client.UserId == 0 { if client.IsSuperUser() {
sync.Permissions = proto.Uint64(uint64(AllPermissions)) sync.Permissions = proto.Uint64(uint64(AllPermissions))
} else { } else {
server.HasPermission(client, server.root, EnterPermission) server.HasPermission(client, server.root, EnterPermission)
@ -532,7 +544,7 @@ func (server *Server) sendUserList(client *Client) {
// Send a client its permissions for channel. // Send a client its permissions for channel.
func (server *Server) sendClientPermissions(client *Client, channel *Channel) { func (server *Server) sendClientPermissions(client *Client, channel *Channel) {
// No caching for SuperUser // No caching for SuperUser
if client.UserId == 0 { if client.IsSuperUser() {
return return
} }

View file

@ -35,5 +35,5 @@ func NewUser(id uint32, name string) (user *User, err os.Error) {
return &User{ return &User{
Id: id, Id: id,
Name: name, Name: name,
}, nil },nil
} }